[带修莫队] 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; }
相关文章推荐
- BZOJ 2120: 数颜色/BZOJ 2453: 维护队列 带修改莫队
- [Bzoj2120]数颜色 (非正解 )(莫队)
- bzoj 2120: 数颜色(带修改的莫队算法)
- bzoj 2120 数颜色 莫队超级大暴力
- 【BZOJ 2120】【国家集训队 2011】【数颜色】(莫队)
- 【带修莫队】bzoj2120 数颜色
- 一个假莫队算法总结 (bzoj2021 小z的袜子 bzoj1878 HH的项链 bzoj2120 数颜色)
- [bzoj2120][bzoj2453][莫队算法]数颜色
- [BZOJ2120]数颜色(带修改莫队入门)
- 会修修的莫队--BZOJ2120: 数颜色
- BZOJ 2120 数颜色&2453 维护队列 [带修改的莫队算法]【学习笔记】
- 【BZOJ2120】数颜色,带修莫队
- BZOJ2120 数颜色 【带修改莫队】
- bzoj 2120 数颜色 带修改莫队
- [bzoj2120]数颜色【莫队(带修改)】
- [BZOJ 2120][数颜色][带修改的莫队]
- bzoj 2120 数颜色 带修改莫队
- [BZOJ2120][带修改莫队算法]数颜色
- [BZOJ 2120]数颜色:带修改莫队
- BZOJ 2120 数颜色 (带修莫队)