[带修莫队] Bzoj 2120 数颜色
Posted comfortable
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[带修莫队] Bzoj 2120 数颜色相关的知识,希望对你有一定的参考价值。
Description
墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会像你发布如下指令: 1、 Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔。 2、 R P Col 把第P支画笔替换为颜色Col。为了满足墨墨的要求,你知道你需要干什么了吗?
Input
第1行两个整数N,M,分别代表初始画笔的数量以及墨墨会做的事情的个数。第2行N个整数,分别代表初始画笔排中第i支画笔的颜色。第3行到第2+M行,每行分别代表墨墨会做的一件事情,格式见题干部分。
Output
对于每一个Query的询问,你需要在对应的行中给出一个数字,代表第L支画笔到第R支画笔中共有几种不同颜色的画笔。
Sample Input
1 2 3 4 5 5
Q 1 4
Q 2 6
R 1 2
Q 1 4
Q 2 6
Sample Output
4
3
4
HINT
对于100%的数据,N≤10000,M≤10000,修改操作不多于1000次,所有的输入数据中出现的所有整数均大于等于1且不超过10^6。
题解
-
可修改的莫队,怎么做呢?
-
普通的莫队做法肯定会爆炸
-
我们可以先引入一个“修改时间”,表示当前询问是发生在前Time个修改后的。
-
也就是说我们在做莫队的时候除了原先的两个l,r指针,还引入时间指针,可以通过时间倒流或时光推移来保证正确性
-
按照原先的sort函数来说,使得每个询问最坏情况下时间指针可以移动n次,总共就n^2次,极其不优秀,那么下面我们就要用三关键字排序来做
-
时间复杂度分析:(num=sqrt(n))
-
①对于l指针,依旧是O(num*n)
-
②对于r指针,也依旧是O(n*n/num)
-
③对于t指针(时间指针):
-
我们要寻找有多少个单调段(一个单调段下来最多移动n次) 在排序函数里,当且仅当两个询问l在同块,r也在同块时,才会对可怜的t进行排序。
-
对于每一个l的块,里面r最坏情况下占据了所有的块
-
所以最坏情况下:有n/num个l的块,每个l的块中会有n/num个r的块,此时,在一个r块里,就会出现有序的t。
-
所以t的单调段个数为:(n/unit)^2。
-
每个单调段最多移动n次。 最后所以时间指针的时间复杂度为 O((n/num)^2*n)
-
三个指针汇总:O(num*n+n^2/num+(n/num)^2*n)。当num=2/3n时,时间最优秀,为O(n^3/5)
代码
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 #include <cmath> 5 #define N 10010 6 using namespace std; 7 struct Query{int l,r,t,d;}q[N]; 8 struct Change{int w,l,r;}p[N]; 9 int n,m,ans,l=1,r,k,a[N],col[N*100],Time,numq,now[N],num,bel[N],Ans[N]; 10 bool cmp(Query a,Query b) { return bel[a.l]==bel[b.l]?(bel[a.r]==bel[b.r]?a.t<b.t:a.r<b.r):a.l<b.l; } 11 void change(int x,int y) { col[x]+=y; if (y>0) ans+=col[x]==1; if (y<0) ans-=col[x]==0; } 12 void pd(int x,int y) { if (l<=x&&x<=r) change(y,1),change(a[x],-1); a[x]=y; } 13 int main() 14 { 15 scanf("%d%d",&n,&m),num=pow(n,0.66666); 16 for (int i=1;i<=n;i++) scanf("%d",&a[i]),now[i]=a[i],bel[i]=i/num+1; 17 for (int i=1,x,y;i<=m;i++) 18 { 19 char ch; 20 scanf(" %c %d%d",&ch,&x,&y); 21 if (ch==‘Q‘) q[++numq]=(Query){x,y,Time,numq}; 22 if (ch==‘R‘) p[++Time]=(Change){x,y,now[x]},now[x]=y; 23 } 24 sort(q+1,q+numq+1,cmp); 25 for (int i=1;i<=numq;i++) 26 { 27 while (k<q[i].t) pd(p[k+1].w,p[k+1].l),k++; 28 while (k>q[i].t) pd(p[k].w,p[k].r),k--; 29 while (l<q[i].l) change(a[l],-1),l++; 30 while (l>q[i].l) change(a[l-1],1),l--; 31 while (r<q[i].r) change(a[r+1],1),r++; 32 while (r>q[i].r) change(a[r],-1),r--; 33 Ans[q[i].d]=ans; 34 } 35 for (int i=1;i<=numq;i++) printf("%d ",Ans[i]); 36 }
以上是关于[带修莫队] Bzoj 2120 数颜色的主要内容,如果未能解决你的问题,请参考以下文章