【BZOJ2473/2120】维护队列 分块+二分
Description
你小时候玩过弹珠吗?
小朋友A有一些弹珠,A喜欢把它们排成队列,从左到右编号为1到N。为了整个队列鲜艳美观,小朋友想知道某一段连续弹珠中,不同颜色的弹珠有多少。当然,A有时候会依据个人喜好,替换队列中某个弹珠的颜色。但是A还没有学过编程,且觉得头脑风暴太浪费脑力了,所以向你来寻求帮助。
Input
输入文件第一行包含两个整数N和M。
第二行N个整数,表示初始队列中弹珠的颜色。
接下来M行,每行的形式为“Q L R”或“R x c”,“Q L R”表示A想知道从队列第L个弹珠到第R个弹珠中,一共有多少不同颜色的弹珠,“R x c”表示A把x位置上的弹珠换成了c颜色。
Output
对于每个Q操作,输出一行表示询问结果。
Sample Input
2 3
1 2
Q 1 2
R 1 2
Q 1 2
Sample Output
2
1
1
HINT
对于100%的数据,有1 ≤ N ≤ 10000, 1 ≤ M ≤ 10000,小朋友A不会修改超过1000次,所有颜色均用1到10^6的整数表示。
Source
惭愧,又看了黄学长题解。。。引入一个pre数组,记录前一个相同颜色的位置,块内排序,有点像一个链?,然后查询时只要比pre【i】比l小,则同一个块内前面的都满足。
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <cmath> 6 #define N 10010 7 using namespace std; 8 int last[1000100],pre[N],a[N],b[N],pos[N]; 9 int n,m,q,block; 10 void build() 11 { 12 for (int i=1;i<=n;i++) 13 { 14 b[i]=last[a[i]]; 15 last[a[i]]=i; 16 pos[i]=(i-1)/block+1; 17 } 18 } 19 void make_block(int x) 20 { 21 int l=(x-1)*block+1,r=min(x*block,n); 22 for (int i=l;i<=r;i++) pre[i]=b[i]; 23 sort(pre+l,pre+r+1); 24 } 25 int er_find(int x,int v) 26 { 27 int l=(x-1)*block+1,r=min(x*block,n),l1; 28 l1=l; 29 while (l<=r) 30 { 31 int mid=(l+r)>>1; 32 if (pre[mid]<v) l=mid+1; 33 else r=mid-1; 34 } 35 return l-l1; 36 } 37 int query(int l,int r) 38 { 39 int ans=0; 40 if (pos[l]==pos[r]) {for (int i=l;i<=r;i++) if (b[i]<l) ans++;} 41 else 42 { 43 for (int i=l;i<=pos[l]*block;i++) if (b[i]<l) ans++; 44 for (int i=(pos[r]-1)*block+1;i<=r;i++) if (b[i]<l) ans++; 45 for (int i=pos[l]+1;i<pos[r];i++) ans+=er_find(i,l); 46 } 47 return ans; 48 } 49 void change(int x,int v) 50 { 51 for (int i=1;i<=n;i++) last[a[i]]=0; 52 a[x]=v; 53 for (int i=1;i<=n;i++) 54 { 55 int t=b[i]; 56 b[i]=last[a[i]]; 57 if (t!=b[i]) make_block(pos[i]); 58 last[a[i]]=i; 59 } 60 } 61 int main() 62 { 63 scanf("%d%d",&n,&q); 64 for (int i=1;i<=n;i++) scanf("%d",&a[i]); 65 block=int(sqrt(n)); 66 if (n%block) m=n/block+1; 67 else m=n/block; 68 build(); 69 for (int i=1;i<=m;i++) make_block(i); 70 for (int i=1;i<=q;i++) 71 { 72 char ch[5]; 73 int x,y; 74 scanf("%s%d%d",ch,&x,&y); 75 if (ch[0]=='Q') printf("%d\n",query(x,y)); 76 else change(x,y); 77 } 78 return 0; 79 }
—Anime Otaku Save The World.