首页 > 代码库 > BZOJ 2120: 数颜色

BZOJ 2120: 数颜色

Description

给你一个序列,询问 \([L,R]\) 区间中颜色种数,支持修改操作,不强制在线. \(n,m\leqslant 10^4\)

Sol

三维莫队. QAQ.

简单的说一下吧...

三维莫队就是维护三元组 \((L,R,T)\) 的答案,表示 \([L,R]\) 区间在进行了 \(T\) 次修改后的答案.

然后就可以处理 \(L\pm 1,R\pm 1,T\pm 1\) 的答案了.

关于三维莫队:

我们需要对 \(L,R\) 分块,像处理二维莫队一样按 \(L,R,T\) 的顺序排序,移动 \(L,R\) 直接统计颜色个数移动就可以.

对于 \(T\) 的移动,它表示的其实是一个前缀,那么对于 \(T\) 的移动就可以删去再把新元素加上贡献就可以,使它直接和原来的元素交换,这样不管扩大还是缩小都是适用的.

关于复杂度:

因为需要枚举前两维的块,最后一维直接暴力,那么设块大小为 \(B\) ,则有复杂度

\(O((\frac{n}{B})^2*n+mB)\)

\(O(\frac{n^3}{B^2}+mB)\)

求导.

\(m+n^3*(-2)*B^{-3}=0\)

\(B^3=\frac{n^3}{m}\)

因为 \(n,m\) 同阶,

\(B^3=n^2\)

\(B=n^{\frac{2}{3}}\)

所以复杂度为 \(O(n^{\frac{5}{3}})\) .

PS1:从这篇博客开始写简述题意

PS2:复杂度证明问的TA爷 QAQ.

PS3:三维莫队其实没用QAQ,跑不了 \(10^5\) 也就跑跑 \(10^4\)

Code

/**************************************************************    Problem: 2120    User: BeiYu    Language: C++    Result: Accepted    Time:2232 ms    Memory:5720 kb****************************************************************/ #include<cstdio>#include<cmath>#include<utility>#include<vector>#include<algorithm>#include<cstring>#include<iostream>using namespace std; const int N = 10005;const int M = 1000005;#define mpr(a,b) make_pair(a,b) int n,m,B,cp,cq;int a[N],c[M];int b1[N],b2[N];int L,R,T,ans;pair<int,int> s[N]; struct Q{ int l,r,t,id; }p[N],q[N];bool operator < (const Q &a,const Q &b){    if(b1[a.l]!=b1[b.l]) return b1[a.l]<b1[b.l];    if(b2[a.r]!=b2[b.r]) return b2[a.r]<b2[b.r];    return a.t<b.t;} inline int in(int x=0,char ch=getchar()){ while(ch>‘9‘||ch<‘0‘) ch=getchar();    while(ch>=‘0‘&&ch<=‘9‘) x=(x<<3)+(x<<1)+ch-‘0‘,ch=getchar();return x; } void Move(int x,int v){    if(v==-1){ if((--c[a[x]])==0) ans--; }    else{ if((++c[a[x]])==1) ans++; }}void Update(int x){    if(L<=p[x].l&&p[x].l<=R) Move(p[x].l,-1);    swap(p[x].r,a[p[x].l]);    if(L<=p[x].l&&p[x].l<=R) Move(p[x].l,1);} int main(){//  freopen("in.in","r",stdin);    n=in(),m=in();    for(int i=1;i<=n;i++) a[i]=in();    for(int i=1;i<=m;i++){        char ch=getchar();while(ch>‘Z‘||ch<‘A‘) ch=getchar();        int u=in(),v=in();        if(ch==‘R‘) p[++cp]=(Q){ u,v,0,0 };        else q[++cq]=(Q){ u,v,cp,i };    }B=pow(n,5.0/3);    for(int i=1;i<=n;i++) b1[i]=b2[i]=(i-1)/B+1;    sort(q+1,q+cq+1);    Move(1,1),L=R=1,T=0;    for(int i=1;i<=cq;i++){        while(R<q[i].r) Move(++R,+1);while(R>q[i].r) Move(R--,-1);        while(L<q[i].l) Move(L++,-1);while(L>q[i].l) Move(--L,+1);        while(T>q[i].t) Update(T--);while(T<q[i].t) Update(++T);//      cout<<L<<" "<<R<<" "<<T<<" "<<ans<<endl;        s[i]=mpr(q[i].id,ans);    }sort(s+1,s+cq+1);    for(int i=1;i<=cq;i++) printf("%d\n",s[i].second);    return 0;}

  

BZOJ 2120: 数颜色