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。
正解:分块
解题报告:
看到这道题我的第一感觉是,咦,暴力可做?!我这种蒟蒻果然第一个想的是暴力。
考虑分块,维护一个pre数组,我们可以把询问视为对于一个区间[l,r]查询有多少个元素的pre小于l。是不是觉得分块很可做??
但是我发现我的分块比较萎,和暴力差不多,后来发现其实是因为修改的时候每次发现改变了颜色之后我要全部重构一遍,然而我并不知道怎么改,就这样吧。。。
1 //It is made by jump~ 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cstdio> 6 #include <cmath> 7 #include <algorithm> 8 #include <ctime> 9 #include <vector> 10 #include <queue> 11 #include <map> 12 #include <set> 13 #ifdef WIN32 14 #define OT "%I64d" 15 #else 16 #define OT "%lld" 17 #endif 18 using namespace std; 19 typedef long long LL; 20 const int MAXN = 10011; 21 const int MAXC = 1000011; 22 int n,m,size,tot,ans; 23 int a[MAXN],belong[MAXN],last[MAXC]; 24 int pre[MAXN],pre_sort[MAXN]; 25 char ch[12]; 26 //相当于是查询区间里有多少个元素pre<l 27 28 inline int getint() 29 { 30 int w=0,q=0; 31 char c=getchar(); 32 while((c<'0' || c>'9') && c!='-') c=getchar(); 33 if (c=='-') q=1, c=getchar(); 34 while (c>='0' && c<='9') w=w*10+c-'0', c=getchar(); 35 return q ? -w : w; 36 } 37 38 inline void rebuild(int x){ 39 int l=(x-1)*size+1,r=x*size; 40 for(int i=l;i<=r;i++) pre_sort[i]=pre[i]; 41 sort(pre_sort+l,pre_sort+r+1); 42 } 43 44 inline void Init(){ 45 int block=sqrt(n); if(n%block) size=block+1; else tot=size=block; 46 if(n%size) tot=n/size+1; else tot=n/size; 47 for(int i=1;i<=n;i++) { 48 a[i]=getint(); belong[i]=(i-1)/size+1; 49 pre[i]=last[a[i]]; last[a[i]]=i; 50 } 51 for(int i=1;i<=tot;i++) rebuild(i); 52 } 53 54 inline int search(int x,int val) { 55 int l=(x-1)*size+1,r=x*size,mid; int cun=l; 56 int pos=l-1;//注意一下如果不能更新应该返回0 57 while(l<=r) { 58 mid=(l+r)>>1; 59 if(pre_sort[mid]<val) pos=mid,l=mid+1; 60 else r=mid-1; 61 } 62 return pos-cun+1; 63 } 64 65 inline void ask(){ 66 int x,y; x=getint(); y=getint(); 67 ans=0; 68 if(belong[x]==belong[y]) { 69 for(int i=x;i<=y;i++) if(pre[i]<x) ans++; 70 printf("%d ",ans); return ; 71 } 72 for(int i=x;i<=belong[x]*size;i++) if(pre[i]<x) ans++; 73 for(int i=(belong[y]-1)*size+1;i<=y;i++) if(pre[i]<x) ans++; 74 for(int i=belong[x]+1;i<belong[y];i++) ans+=search(i,x); 75 printf("%d ",ans); 76 } 77 78 inline void update(){ 79 for(int i=1;i<=n;i++) last[a[i]]=0; 80 int x,y; x=getint(); y=getint(); 81 a[x]=y; 82 for(int i=1;i<=n;i++) { 83 if(pre[i]!=last[a[i]]) { 84 pre[i]=last[a[i]]; 85 rebuild(belong[i]); 86 } 87 last[a[i]]=i; 88 } 89 } 90 91 inline void work(){ 92 n=getint(); m=getint(); 93 Init(); 94 while(m--) { 95 scanf("%s",ch); 96 if(ch[0]=='Q') ask(); 97 else update(); 98 } 99 } 100 101 int main() 102 { 103 work(); 104 return 0; 105 }