【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 }
View Code

莫队

  对于莫队来说,难点就在于它带有修改操作。我们怎么来处理修改呢?我们在除了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 }
View Code

 

posted @ 2018-09-05 00:57  蒟蒻LQL  阅读(278)  评论(0编辑  收藏  举报