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
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
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 ",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 ",query(x,y)); 74 else change(x,y); 75 } 76 return 0; 77 }