您的位置:首页 > 其它

[带修莫队] BZOJ2120: 数颜色

2017-04-27 22:18 267 查看

题意

给出一个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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: