【BZOJ 2120】数颜色【分块/莫队】
题意
给出n个数字和m个操作。操作有两种。1:查询区间[l,r]内不同种类得数字个数。2: 将下标为p得数字修改为v
分析
如果不是修改操作的话,用莫队贼简单就可以水过,但是因为带了修改就有一些麻烦了。
分块
开一个数组pre[i]记录上一个和第i个元素相同元素得位置。那么对于区间[l,r],当pre[i]<l的时候,ans++。完整块内就可以直接二分查找,不完整块直接暴力。修改是直接暴力修改因为它保证修改操作不会超过1000次。
下面是代码
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 #include <cmath> 6 using namespace std; 7 const int maxn=10000+10; 8 int a[maxn],belong[maxn],L[maxn],R[maxn],pre[maxn]; 9 int last[1000000+100],b[maxn]; 10 11 int n,m,cnt,block; 12 void update(int p,int v){ 13 for(int i=1;i<=n;i++) 14 last[a[i]]=0; 15 a[p]=v; 16 for(int i=1;i<=n;i++){ 17 b[i]=last[a[i]]; 18 last[a[i]]=i; 19 } 20 for(int i=1;i<=cnt;i++){ 21 for(int j=L[i];j<=R[i];j++) 22 pre[j]=b[j]; 23 sort(pre+L[i],pre+R[i]+1); 24 } 25 } 26 int Find(int p,int v){ 27 int res=1; 28 int l=L[p],r=R[p]; 29 while(l<=r){ 30 int m=l+(r-l)/2; 31 if(pre[m]<v){ 32 res=m; 33 l=m+1; 34 }else{ 35 r=m-1; 36 } 37 } 38 return res-L[p]+1; 39 } 40 41 int query(int l,int r){ 42 int res=0; 43 if(belong[l]==belong[r]){ 44 for(int i=l;i<=r;i++){ 45 if(b[i]<l) 46 res++; 47 } 48 return res; 49 } 50 for(int i=l;i<=R[belong[l]];i++) 51 if(b[i]<l) 52 res++; 53 54 for(int i=L[belong[r]];i<=r;i++) 55 if(b[i]<l) 56 res++; 57 58 for(int i=belong[l]+1;i<belong[r];i++){ 59 res+=Find(i,l); 60 } 61 return res; 62 } 63 64 int main(){ 65 scanf("%d%d",&n,&m); 66 for(int i=1;i<=n;i++){ 67 scanf("%d",&a[i]); 68 b[i]=last[a[i]]; 69 last[a[i]]=i; 70 } 71 block=sqrt(n);cnt=n/block; 72 if(n%block)cnt++; 73 for(int i=1;i<=n;i++) 74 belong[i]=(i-1)/block+1; 75 for(int i=1;i<=cnt;i++) 76 L[i]=(i-1)*block+1,R[i]=i*block; 77 R[cnt]=n; 78 79 for(int i=1;i<=cnt;i++){ 80 for(int j=L[i];j<=R[i];j++) 81 pre[j]=b[j]; 82 sort(pre+L[i],pre+R[i]+1); 83 } 84 char c; 85 int l,r; 86 for(int i=1;i<=m;i++){ 87 scanf(" %c",&c); 88 if(c=='Q'){ 89 scanf("%d%d",&l,&r); 90 printf("%d\n",query(l,r)); 91 }else{ 92 scanf("%d%d",&l,&r); 93 update(l,r); 94 } 95 } 96 return 0; 97 }
莫队
对于莫队来说,难点就在于它带有修改操作。我们怎么来处理修改呢?我们在除了l,r指针以外再增加一个指针now,用类似l和r得方式进行维护。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 #include <cmath> 6 7 using namespace std; 8 const int maxn=10000+100; 9 int belong[maxn],val[maxn]; 10 struct Node{ 11 int L,R,id,tim; 12 bool operator<(const Node& rhs)const{ 13 return belong[L]==belong[rhs.L]?(belong[R]==belong[rhs.R]?tim<rhs.tim:R<rhs.R):L<rhs.L; 14 } 15 int ans; 16 }ask[maxn]; 17 struct Up{ 18 int p,v,z; 19 }up[maxn]; 20 int num1,num2; 21 int cmp(Node a,Node b){ 22 return a.id<b.id; 23 } 24 int n,q; 25 int f[1000000+100],ans,block,l,r,now; 26 void update(int p,int addv){ 27 if(addv>0){ 28 f[val[p]]++; 29 if(f[val[p]]==1) 30 ans++; 31 }else{ 32 f[val[p]]--; 33 if(f[val[p]]==0) 34 ans--; 35 } 36 } 37 void in_time(int x){ 38 if(up[x].p>=l&&up[x].p<=r){ 39 update(up[x].p,-1); 40 } 41 up[x].z=val[up[x].p]; 42 val[up[x].p]=up[x].v; 43 if(up[x].p>=l&&up[x].p<=r){ 44 update(up[x].p,1); 45 } 46 } 47 void out_time(int x){ 48 if(up[x].p>=l&&up[x].p<=r) 49 update(up[x].p,-1); 50 val[up[x].p]=up[x].z; 51 if(up[x].p>=l&&up[x].p<=r) 52 update(up[x].p,1); 53 } 54 55 void solve(){ 56 l=1,r=0,now=0; 57 for(int i=1;i<=num1;i++){ 58 if(r<ask[i].R){ 59 for(r=r+1;r<ask[i].R;r++) 60 update(r,1); 61 update(r,1); 62 } 63 if(l>ask[i].L){ 64 for(l=l-1;l>ask[i].L;l--) 65 update(l,1); 66 update(l,1); 67 } 68 if(r>ask[i].R){ 69 for(;r>ask[i].R;r--) 70 update(r,-1); 71 } 72 if(l<ask[i].L){ 73 for(;l<ask[i].L;l++) 74 update(l,-1); 75 } 76 if(now<ask[i].tim){ 77 for(now=now+1;now<ask[i].tim;now++) 78 in_time(now); 79 in_time(now); 80 } 81 if(now>ask[i].tim){ 82 for(;now>ask[i].tim;now--) 83 out_time(now); 84 } 85 ask[i].ans=ans; 86 } 87 } 88 89 int main(){ 90 scanf("%d%d",&n,&q); 91 for(int i=1;i<=n;i++){ 92 scanf("%d",&val[i]); 93 } 94 block=sqrt(n); 95 for(int i=1;i<=n;i++) 96 belong[i]=(i-1)/block+1; 97 char c; 98 int l,r; 99 for(int i=1;i<=q;i++){ 100 scanf(" %c",&c); 101 if(c=='Q'){ 102 num1++; 103 scanf("%d%d",&ask[num1].L,&ask[num1].R); 104 ask[num1].id=num1;ask[num1].tim=num2; 105 }else{ 106 num2++; 107 scanf("%d%d",&up[num2].p,&up[num2].v); 108 up[num2].z=0; 109 } 110 } 111 sort(ask+1,ask+1+num1); 112 solve(); 113 sort(ask+1,ask+1+num1,cmp); 114 for(int i=1;i<=num1;i++) 115 printf("%d\n",ask[i].ans); 116 117 return 0; 118 }