题意
给出一个n个元素的序列a。执行m次操作:
1. Q L R代表询问[L,R]有几种不同的数字。
2. R x y 把第a[x]改为y。
题解
带修莫队裸题。
怎么搞带修莫队呢?就是加一维时间,然后对L,R都分块。块的大小定为
n23
。
具体来说,先对L分块,对与同一L块中再对R分块。
bool operator < (const data1 &b)const{
if(blg[L]==blg[b.L]){
if(blg[R]==blg[b.R]) return tim<b.tim;
return R<b.R;
}
return L<b.L;
}
之后的过程就和普通莫队差不多了,当time移动时就把对应那些修改操作执行/撤销即可。
最重要的是复杂度。
要注意由于多加了一维,我们分块大小需要为
n23
才能得到更好的复杂度。这是为什么呢?
我们设分块大小为
nw
,并设n与m同阶:
- 考虑L的移动
1. 同一L块,每次 O(nw) ,有m次询问,共 O(nw+1)
2. 跨越不同L块,每次 O(nw) ,有 O(n1−w) 块,共 O(n) - 考虑R的移动
1. 同一L块且同一R块,每次 O(nw) ,有 O(n1−w∗n1−w)=O(n2−2w) 次,共 O(n2−w)
2. 跨越不同L块,每次 O(n) ,有 O(n1−w) 次,共 O(n2−w)
3. 同一L块且跨越不同R块,每次 O(nw) ,有 O(n2−2w) 次,共有 O(n2−w) - 考虑time的移动
1. 同一L块且同一R块,time递增,共 O(n) 。
2. 同一L块且跨越R块,每次 O(n) ,有 O(n2−2w) 次,共 O(n3−2w)
3. 跨越L块,每次O(n),有 O(n1−w) 次,共 O(n2−w)
综上所述,算法总复杂度为
O(nmin(3−2w,w+1))
,
w∈(0,1)
所以当w=
23
时取到最小,总复杂度为
O(n53)
这下就没问题了。
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=10005,maxw=1000005;
int n,m,m1,m2,sum[maxw],res,ans[maxn],w[maxn],b[maxn],blg[maxn];
struct data1{
int L,R,tim,id;
bool operator < (const data1 &b)const{
if(blg[L]==blg[b.L]){
if(blg[R]==blg[b.R]) return tim<b.tim;
return R<b.R;
}
return L<b.L;
}
} q[maxn];
struct data2{ int pos,v[2]; } op[maxn];
void Updata(int x,int k){
if(k==1) res=(sum[x]++)?res:res+1;
else res=(--sum[x])?res:res-1;
}
void Change(int L,int R,int id,int k){
if(L<=op[id].pos&&op[id].pos<=R) Updata(w[op[id].pos],-1), Updata(op[id].v[k],1);
w[op[id].pos]=op[id].v[k];
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&w[i]), b[i]=w[i];
for(int i=1;i<=m;i++){
char ch=getchar(); while(ch!='Q'&&ch!='R') ch=getchar();
if(ch=='Q'){
m1++; scanf("%d%d",&q[m1].L,&q[m1].R);
q[m1].tim=m2; q[m1].id=m1;
} else{
m2++; scanf("%d%d",&op[m2].pos,&(op[m2].v[1]));
op[m2].v[0]=b[op[m2].pos]; b[op[m2].pos]=op[m2].v[1];
}
}
int blk=pow(n,2.0/3);
for(int i=1;i<=n;i++) blg[i]=(i-1)/blk+1;
sort(q+1,q+1+m1);
Updata(w[1],1);
for(int L=1,R=1,now=0,i=1;i<=m1;i++){
while(now<q[i].tim) Change(L,R,++now,1);
while(now>q[i].tim) Change(L,R,now--,0);
while(L<q[i].L) Updata(w[L++],-1);
while(L>q[i].L) Updata(w[--L],1);
while(R<q[i].R) Updata(w[++R],1);
while(R>q[i].R) Updata(w[R--],-1);
ans[q[i].id]=res;
}
for(int i=1;i<=m1;i++) printf("%d\n",ans[i]);
return 0;
}