【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

HINT

 

对于100%的数据,有1 ≤ N ≤ 10000, 1 ≤ M ≤ 10000,小朋友A不会修改超过1000次,所有颜色均用1到10^6的整数表示。

 

Source

2011福建集训

 惭愧,又看了黄学长题解。。。引入一个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 } 
View Code

 

posted @ 2016-03-09 20:32  DMoon  阅读(186)  评论(0编辑  收藏  举报