下面的同学们搞怪了
好的,话不多说,我来讲这道题时顺便就来讲讲带修莫队
不知道普通莫队是什么的请参见我之前为小Z的袜子写的博客
首先来审审题意:多个区间询问,询问[l,r]中颜色的种类数。可以单点修改颜色。
莫队可以修改???
那么我们切入正题
这类问题被称为带修莫队(可持久化莫队)。
类比到主席树,即可持久化线段树,可以引入一个“修改时间”,表示当前询问是发生在前time个修改操作后的。也就是说,在进行莫队算法时,看看当前的询问和时间指针(第三个指针,别忘了s,e)是否相符,然后进行时光倒流(向前)或者时光推移(向后)操作来维护答案。
原本sort的构造。仅靠原来的sort关键字会使得枚举每个询问都可能因为时间指针移动的缘故要移动n次,总共就n^2次,那还不如写暴力。
所以为了防止这样的事情发生,大神们(我)再加入第三关键字tim:
bool cmp(Node a,Node b)
{
return Be[a.l]==Be[b.l]?(Be[a.r]==Be[b.r]?a.tim<b.tim:a.r<b.r):a.l<b.l;
}
Be数组的意义是记录分块大小
上次忘说了请见谅
接着就是时间复杂度
首先,r和tim的关系就像l和r的关系一样:只有在前后者处于同块时,后者才会因排序而有序,否则sort会去满足前者,使得后者开始乱跳。
依旧像上文那样:枚举m个答案,就一个m了。设分块大小为size。
分类讨论:
①对于l指针,依旧是O(size*n)
②对于r指针,依旧是O(n*n/size)
③对于tim指针:
类比r时间复杂度的计算。我们要寻找有多少个单调段(一个单调段下来最多移动n次)。上文提到,当且仅当两个询问l在同块,r也在同块时,才会对tim进行排序。对于每一个l的块,里面r最坏情况下占据了所有的块,所以最坏情况下:有n/size个l的块,每个l的块中会有n/size个r的块,此时,在一个r块里,就会出现有序的tim。所以tim的单调段个数为:(n/size)*(n/size)。每个单调段最多移动n次。
所以,其复杂度=O((n/size)2*n)
三个指针汇总:O(sizen+n^2/size+(n/size)^2n)
当size=n*sqrt(n)时,复杂度取到最高:
为
O(n^(5/3))!!!
接下来是代码
#include<stdio.h>
#include<algorithm>
#include<math.h>
#define go(i,a,b) for(int i=a;i<=b;i++)
using namespace std;const int N=10005;
struct Node{
int l,r,tim,ID;
}q[N];
struct Change{
int pos,now,bef;
}c[N];
int n,m,s[N],color[1000005],t,time,now[N],size,Be[N],ans[N],Ans,l=1,r,T;
bool cmp(Node a,Node b)
{
return Be[a.l]==Be[b.l]?(Be[a.r]==Be[b.r]?a.tim<b.tim:a.r<b.r):a.l<b.l;
}
void revise(int x,int d)
{
color[x]+=d;
if(d>0)Ans+=color[x]==1;
else if(d<0)Ans-=color[x]==0;
}
void going(int x,int d)
{
if(l<=x&&x<=r)revise(d,1),revise(s[x],-1);
s[x]=d;
}
int main(){
scanf("%d%d",&n,&m);size=pow(n,0.666666);
go(i,1,n)scanf("%d",&s[i]),now[i]=s[i],Be[i]=i/size+1;
go(i,1,m){char sign;int x,y;scanf(" %c %d%d",&sign,&x,&y);
if(sign==‘Q‘)q[++t]=(Node){x,y,time,t};
if(sign==‘R‘)c[++time]=(Change){x,y,now[x]},now[x]=y;
}
sort(q+1,q+t+1,cmp);
go(i,1,t)
{
while(T<q[i].tim)going(c[T+1].pos,c[T+1].now),T++;
while(T>q[i].tim)going(c[T].pos,c[T].bef),T--;
while(l<q[i].l)revise(s[l],-1),l++;
while(l>q[i].l)revise(s[l-1],1),l--;
while(r<q[i].r)revise(s[r+1],1),r++;
while(r>q[i].r)revise(s[r],-1),r--;
ans[q[i].ID]=Ans;
}
go(i,1,t)printf("%d\n",ans[i]);
return 0;
}