BZOJ2120 数颜色 分块+二分法
Posted WDZRMPCBIT
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ2120 数颜色 分块+二分法相关的知识,希望对你有一定的参考价值。
题意:给定一个颜色序列,维护:1、单点修改 2、区间查询不同颜色的种数
题解:
定义f[i]为i左边第一个和i颜色相同的位置,用分块来维护f。
询问:看区间中有多少个位置的f[i]<l
更新:暴力枚举p左右最近的与p颜色相同的位置,更新即可
#include <cmath> #include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; const int MAXS=100+2; const int MAXC=1000000+2; struct BLOCK{ int a[MAXS],b[MAXS],c[MAXS]; }block[MAXS]; int N,M,S,C,f[MAXC]; char s[3]; void Change(int x,int c){ int p=(x-1)/S+1,m=(1+S)>>1; for(int l=1,r=S;l<r;m=(l+r)>>1){ if(block[p].b[m]<block[p].a[x-(p-1)*S]) l=m+1; else r=m; } block[p].b[m]=c; while(m!=1 && block[p].b[m-1]>block[p].b[m]) swap(block[p].b[m-1],block[p].b[m]),m--; while(m!=S && block[p].b[m+1]<block[p].b[m]) swap(block[p].b[m+1],block[p].b[m]),m++; block[p].a[x-(p-1)*S]=c; } void Update(int x,int c){ int p=(x-1)/S+1,t=-1; for(int i=x+1;i<=N;i++){ if(block[(i-1)/S+1].c[i-(i-1)/S*S]==block[p].c[x-(p-1)*S]){ Change(i,block[p].a[x-(p-1)*S]); break; } } for(int i=x+1;i<=N;i++) if(block[(i-1)/S+1].c[i-(i-1)/S*S]==c){ Change(i,x); break; } Change(x,-1); for(int i=x-1;i;i--) if(block[(i-1)/S+1].c[i-(i-1)/S*S]==c){ Change(x,i); break; } block[p].c[x-S*(p-1)]=c; } int Find(int p,int t){ int m=(1+S)>>1,l=1,r=S; while(l<r){ if(block[p].b[m]>=t) r=m-1; else l=m+1; m=(l+r)>>1; } if(block[p].b[l]>=t) l--; return l; } int Query(int l,int r){ int ret=0,m=(1+S)>>1,t=l; if((l-1)%S){ int p=(l-1)/S+1; for(int i=l-S*(p-1);i<=S && i<=r-S*(p-1);i++) if(block[p].a[i]<t) ret++; l=S*p+1; } while(l+S-1<=r) ret+=Find((l-1)/S+1,t),l+=S; if(r%S){ int p=l/S+1; for(int i=1;i<=r-S*(p-1);i++) if(block[p].a[i]<t) ret++; } return ret; } int main(){ memset(f,-1,sizeof(f)); memset(block,0X7F,sizeof(block)); scanf("%d %d",&N,&M),S=ceil(sqrt((double)N)); for(int i=1,j=1,k=1,c;i<=N;i++,j++){ scanf("%d",&block[k].c[j]); block[k].a[j]=block[k].b[j]=f[block[k].c[j]],f[block[k].c[j]]=i; if(j==S || i==N){ sort(block[k].b+1,block[k].b+j+1); j=0,k++; } } C=(N%S?N/S+1:N/S); for(int i=1,a,b;i<=M;i++){ scanf("%s %d %d",s,&a,&b); if(s[0]==\'R\') Update(a,b); if(s[0]==\'Q\') printf("%d\\n",Query(a,b)); } return 0; }
以上是关于BZOJ2120 数颜色 分块+二分法的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ2453: 维护队列&&BZOJ2120: 数颜色 二分+分块 双倍经验