BZOJ-2120-数颜色(暴力/分块)

Description

墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会像你发布如下指令: 1、 Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔。 2、 R P Col 把第P支画笔替换为颜色Col。为了满足墨墨的要求,你知道你需要干什么了吗?

Input

第1行两个整数N,M,分别代表初始画笔的数量以及墨墨会做的事情的个数。第2行N个整数,分别代表初始画笔排中第i支画笔的颜色。第3行到第2+M行,每行分别代表墨墨会做的一件事情,格式见题干部分。

Output

对于每一个Query的询问,你需要在对应的行中给出一个数字,代表第L支画笔到第R支画笔中共有几种不同颜色的画笔。

Sample Input

6 5
1 2 3 4 5 5
Q 1 4
Q 2 6
R 1 2
Q 1 4
Q 2 6

Sample Output

4
4
3
4

HINT

 

对于100%的数据,N≤10000,M≤10000,修改操作不多于1000次,所有的输入数据中出现的所有整数均大于等于1且不超过10^6。


2016.3.2新加数据两组by Nano_Ape

 

Source

 

题解

这道题暴力也可以水过(但是不知道为什么离散化后效率会快很多0.0)

 1 #include<bits/stdc++.h>
 2 #define N 10005
 3 #define M 1000005
 4 using namespace std;
 5 int n,m;
 6 int a[N];
 7 int f[M],flag[M];
 8 char st[5];
 9 inline int read(){
10     int x=0,f=1; char ch=getchar();
11     while (ch>'9'||ch<'0'){ if (ch=='-') f=-1; ch=getchar(); }
12     while (ch<='9'&&ch>='0'){ x=(x<<3)+(x<<1)+ch-'0'; ch=getchar(); }
13     return x*f;
14 }
15 int main(){
16     n=read(); m=read();
17     int top=0;
18     for (int i=1;i<=n;i++){
19         a[i]=read();
20         if (!f[a[i]]) f[a[i]]=++top;
21         a[i]=f[a[i]];
22     }
23     for (int i=1;i<=m;i++){
24         scanf("%s",st);
25         int x=read(),y=read();
26         if (st[0]=='Q'){
27             int ans=0;
28             for (int j=x;j<=y;j++)
29                 if (flag[a[j]]!=i) ans++,flag[a[j]]=i;
30             printf("%d\n",ans);
31         } else{
32             if (!f[y]) f[y]=++top;
33             a[x]=f[y];
34         }
35     }
36     return 0;
37 } 
暴力

当然我们要去思考一些别的算法

这道题参考了一下hzw学长

我们用pre[i]表示前一个和i颜色相同的笔的位置

询问[l,r]的时候如果pre[i]<l说明这段区间没有和i颜色相同的笔,ans++

所以对于这段区间,我们可以用分块大法

对于每一块内的pre值排个序,整个块的查询二分即可

 1 #include<bits/stdc++.h>
 2 #define N 10005
 3 #define M 1000005
 4 using namespace std;
 5 int n,m,blo;
 6 int a[N],b[N],pre[N],t[N];
 7 int last[M];
 8 char st[5];
 9 int read(){
10     int x=0,f=1; char ch=getchar();
11     while (ch>'9'||ch<'0'){ if (ch=='-') f=-1; ch=getchar(); }
12     while (ch<='9'&&ch>='0'){ x=(x<<3)+(x<<1)+ch-'0'; ch=getchar(); }
13     return x*f;
14 }
15 void reset(int x){
16     int l=(x-1)*blo+1,r=min(n,x*blo);
17     for (int i=l;i<=r;i++) pre[i]=t[i];
18     sort(pre+l,pre+r+1);
19 }
20 void build(){
21     for (int i=1;i<=n;i++){
22         t[i]=last[a[i]];
23         last[a[i]]=i;
24     }
25     for (int i=1;i<=b[n];i++) reset(i);
26 }
27 int find(int x,int k){
28     int l=(x-1)*blo+1,r=min(n,x*blo);
29     int st=l;
30     while (l<=r){
31         int mid=(l+r)>>1;
32         if (pre[mid]<k) l=mid+1;
33                     else r=mid-1;
34     }
35     return l-st;
36 } 
37 int query(int l,int r){
38     int ans=0;
39     if (b[l]==b[r]){
40         for (int i=l;i<=r;i++)
41             if (t[i]<l) ans++;
42     } else{
43         for (int i=l;i<=b[l]*blo;i++)
44             if (t[i]<l) ans++;
45         for (int i=(b[r]-1)*blo+1;i<=r;i++)
46             if (t[i]<l) ans++;
47         for (int i=b[l]+1;i<=b[r]-1;i++)
48             ans+=find(i,l);
49     }
50     return ans;
51 }
52 void change(int x,int k){
53     for (int i=1;i<=n;i++) last[a[i]]=0;
54     a[x]=k;
55     for (int i=1;i<=n;i++){
56         int s=t[i];
57         t[i]=last[a[i]];
58         last[a[i]]=i;
59         if (t[i]!=s) reset(b[i]);
60     }
61 }
62 int main(){
63     n=read(); m=read();
64     blo=sqrt(n);
65     for (int i=1;i<=n;i++){
66         a[i]=read();
67         b[i]=(i-1)/blo+1;
68     }
69     build();
70     for (int i=1;i<=m;i++){
71         scanf("%s",st);
72         int x=read(),y=read();
73         if (st[0]=='Q') printf("%d\n",query(x,y));
74                     else change(x,y);
75     }
76     return 0;
77 } 
分块

 

posted @ 2017-11-09 16:06  I__am  阅读(233)  评论(0编辑  收藏  举报