题意:给你一个长为n的序列,给你一个mod,再给你q次询问,每次区间查询P(a) = aF1 + aF2 + ... + an·Fn         F为对应的斐波那契数列,a1为以排好序且不重复的区间内的数

参考博客:https://blog.csdn.net/zearot/article/details/50850792

题解:首先对这道题目我们能够想到用莫队处理区间的查询,那么我们只要想办法把莫队的左右区间扩展和收缩解决就可以,那么怎么解决下一个出现的ai是第几大,以及比ai要大的数后移(或前移)的操作就需要用到线段树的维护,区间维护要移动的距离,正数表示向右,负数表示向左。

斐波那契的一个公式F[i-1]*F[k]+F[i]*F[k+1]=F[i+k],所以只要每次维护两个值,一个是第一行的值,一个是第二行的值,线段树维护要移动的距离,

(图是我盗的,盗自上面的博客)

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <map>
#include <queue>
#include <vector>
#include <cstring>
#include <iomanip>
#include <set>
#include<ctime>
#include<unordered_map>
//CLOCKS_PER_SEC
#define se second
#define fi first
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define Pii pair<int,int>
#define Pli pair<ll,int>
#define ull unsigned long long
#define pb push_back
#define fio ios::sync_with_stdio(false);cin.tie(0)
const int N=3e4+10;
const ull base=163;
const int INF=0x3f3f3f3f;
using namespace std;
int a[N];
struct node {int l,r,id;
}Q[N];
int pos[N];
int L=1,R=0;
int ans=0;
int res[N];
int n,q,m;
int mm=1;//离散化后的个数
int fib[N<<1];
int rnk[N];//记录去重后并且排序的a[i]
int rnkA[N];//记录每个a[i]的第几大
int mp[N];//记录区间内有多少个a[i]
int V[N<<2],VL[N<<2],S[N<<2];//S是记录了区间要移动的长度 正数为向右,负数为向左
bool cmp(node x,node y){if(pos[x.l]==pos[y.l])return x.r<y.r;return pos[x.l]<pos[y.l];
}
void init(){//离散化sort(rnk+1,rnk+1+n);for(int i=2;i<=n;i++){//去重if(rnk[i-1]!=rnk[i]){rnk[++mm]=rnk[i];}}for(int i=1;i<=n;i++){//离散后为得到每个a[i]是第几大而进行二分int l=1,r=mm,ans = 0;while(l<=r){int mid=(l+r)>>1;if(rnk[mid]<=a[i]){l=mid+1;ans=mid;}else r=mid-1;}rnkA[i]=ans;}
}
//接下来所有的操作都是在1--mm这个区间内进行线段树操作
void shift(int rt,int s){int l=(VL[rt]*fib[mm+s]+V[rt]*fib[mm+s+1])%m;int r=(VL[rt]*fib[mm+s-1]+V[rt]*fib[mm+s])%m;V[rt]=l;VL[rt]=r;
}
void pushup(int rt){V[rt]=(V[rt<<1]+V[rt<<1|1])%m;VL[rt]=(VL[rt<<1]+VL[rt<<1|1])%m;
}void pushdown(int rt){if(S[rt]){S[rt<<1]+=S[rt];S[rt<<1|1]+=S[rt];shift(rt<<1,S[rt]);shift(rt<<1|1,S[rt]);S[rt]=0;}
}void move(int x,int l,int r,int rt){if(l==r){V[rt]=VL[rt]=0; return ;}pushdown(rt);int m=(l+r)>>1;if(x<=m){move(x,lson);S[rt<<1|1]--;shift(rt<<1|1,-1);}else move(x,rson);pushup(rt);
}void Insert(int x,int l,int r,int rt){if(l==r){VL[rt]=rnk[l]%m*fib[mm+S[rt]]%m;V[rt]=rnk[l]%m*fib[mm+S[rt]+1]%m;return ;}int m=(l+r)>>1;pushdown(rt);if(x<=m){Insert(x,lson);S[rt<<1|1]++;shift(rt<<1|1,1);}else Insert(x,rson);pushup(rt);
}void del(int x){mp[rnkA[x]]--;if(mp[rnkA[x]]==0)move(rnkA[x],1,mm,1);
}void add(int x){mp[rnkA[x]]++;if(mp[rnkA[x]]==1)Insert(rnkA[x],1,mm,1);
}void getfib(){fib[mm]=0;fib[mm+1]=1;for(int i=2;i<=mm;i++)fib[mm+i]=(fib[mm+i-1]+fib[mm+i-2])%m;for(int i=1;i<=mm;i++)fib[mm-i]=(fib[mm-i+2]-fib[mm-i+1]+m)%m;
}int main(){scanf("%d%d",&n,&m);int sz=sqrt(n);for(int i=1;i<=n;i++){scanf("%d",&a[i]);pos[i]=i/sz;rnk[i]=a[i];}init();getfib();scanf("%d",&q);for(int i=1;i<=q;i++){scanf("%d%d",&Q[i].l,&Q[i].r);Q[i].id=i;}sort(Q+1,Q+1+q,cmp);for(int i=1;i<=q;i++){while(L>Q[i].l){L--;add(L);}while(L<Q[i].l){del(L);L++;}while(R<Q[i].r){R++;add(R);}while(R>Q[i].r){del(R);R--;}res[Q[i].id]=V[1];}for(int i=1;i<=q;i++){printf("%d\n",res[i]);}return 0;
}

转载于:https://www.cnblogs.com/Mrleon/p/8946625.html

CodeForces - 633 H Fibonacci-ish II(莫队+线段树)相关推荐

  1. 牛客练习赛85 数学家的迷题 (带修莫队/线段树)

    题意: 1:将a[id]a[id]a[id]的值改为xxx. 2:令t=a[l]×a[l+1]×...×a[r−1]×a[r]t=a[l]×a[l+1]×...×a[r−1]×a[r]t=a[l]×a ...

  2. HDU - 5381 The sum of gcd(莫队/线段树区间合并)

    题目链接:点击查看 题目大意:给出一个长度为 nnn 的序列,再给出 mmm 次询问,每次询问需要回答区间 [L,R][L,R][L,R] 内所有子区间的 gcdgcdgcd 之和.更具体的,对于询问 ...

  3. SPOJ - DQUERY D-query(莫队/线段树+离线/主席树)

    题目链接:点击查看 题目大意:给出一个由n个数组成的序列,再给出m次查询,每次查询区间[l,r]中有多少个不同的数 题目分析:莫队模板题,直接套板子就好了 有点意思的是函数返回值为布尔类型,然后没有r ...

  4. 51nod-猴猴的比赛【莫队,线段树】

    正题 题目链接:https://www.51nod.com/Contest/Problem.html#contestProblemId=1150 题目大意 给出两颗nnn个点的树,求有多少个点(i,j ...

  5. codeforces 617E XOR and Favorite Number 莫队

    https://vjudge.net/problem/CodeForces-617E 题目大意:给nnn个数,mmm个询问,以及一个数kkk,每次询问要输出[l,r][l,r][l,r]内满足a[i] ...

  6. CodeForces - 617E XOR and Favorite Number(莫队)

    题目链接:点击查看 题目大意:给出一个由n个数组成的数列,现在给出m组询问,每次询问包含一个l和一个r,要求回答在闭区间[l,r]中有多少组(i,j)满足[i,j]闭区间内的所有数的异或和等于k 题目 ...

  7. Hdu 6534 Chika and Friendly Pairs 莫队算法+树状数组

    题目链接 题意求给区间[L,R]中有少对(i,j)满足i<j且abs(a[i]-a[j])<=k. 首先来说暴力的方法就是离散化,然后用树状数组来维护,但是m次询问,m很大,所以说一定会t ...

  8. P4113 [HEOI2012]采花 【树状数组 AC】【莫队/主席树 TLE】

    传送门 题意简述:给定一个长度为 n 的序列,有 m 次询问,每次询问一段区间,求区间中有多少个数出现次数超过 1 次 这道题真的有点恶心...在洛谷上属于莫队,但是莫队会T,数据居然有2e6.莫队的 ...

  9. Bzoj3236:[Ahoi2013]作业:莫队算法+树状数组

    题目链接:3236:[Ahoi2013]作业 这题-- 很水的一道莫队,只要用一个树状数组维护数值出现的前缀和就行就行 然而-- 可怜的我真是T得蛋疼了QAQ 先是写了一发裸莫队,T 卧槽T了? 快速 ...

  10. Codeforces 914D - Bash and a Tough Math Puzzle 线段树,区间GCD

    题意: 两个操作, 单点修改 询问一段区间是否能在至多一次修改后,使得区间$GCD$等于$X$ 题解: 正确思路; 线段树维护区间$GCD$,查询$GCD$的时候记录一共访问了多少个$GCD$不被X整 ...

最新文章

  1. 胡玮炜卸任摩拜CEO,或将成为美团大裁员的开端
  2. Oracle用户密码过期和用户被锁解决方法【转】
  3. python输出文本-Python基础练习,查询文本内容并输出;
  4. 模糊数学笔记:七、模糊综合评判决策
  5. 二进制包方式安装部署三节点k8s
  6. 直播预告 | 亚马逊高级应用科学家熊元骏:人类行为理解研究进展
  7. php去字符串空格,php怎么去掉字符串中空格
  8. linux 内核4.12,Linux Kernel 4.12 发布,最新的稳定版内核
  9. 微博:冬奥期间累计共清理相关违规内容近31万条
  10. 提高Axure设计效率的10条建议 (转)
  11. linux g++ 链接,Linux G++将64位共享库代码链接到静态库
  12. JavaSE基础_java简介和环境搭建_2
  13. golang中值类型/指针类型的变量区别总结
  14. 五子棋算杀c语言,什么是五子棋的做杀
  15. python中哪些词是敏感字词_敏感词库(收集2017年最新最全敏感词) 2017 最新版
  16. win10开启ftp连接不上的正确解决方案
  17. (二十四)美萍酒店管理系统:散客开单
  18. jane street market prediction 冠军方案 经验分享 (1/3)
  19. Photoshop 2023(版本24.0)新增功能和软件下载
  20. 升腾c10,华为ct3100安装nextcloud,KodExplorer网盘

热门文章

  1. Java11完全兼容Java8吗_Java11正式发布,要不要升级请看这里!
  2. Xiao Shenyang's classic lines
  3. 手机内存如何快速自清理
  4. python3 flask 使用Mysql数据库
  5. 使用 sed 替换字符串中最后一次出现的字符
  6. ubuntu CA安装 证书申请
  7. 创建一个Employee类
  8. linux 编辑 iso文件格式,这两款实用的光盘映像文件制作编辑软件让你处理ISO文件易如反掌...
  9. MBR、主分区、扩展分区、逻辑分区、活动分区、系统分区、启动分区讲解
  10. P问题、NP问题、NPC问题(算法复杂性,计算复杂性)