【洛谷P1903 数颜色】

题目描述

  墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会像你发布如下指令:

  1、 Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔。

  2、 R P Col 把第P支画笔替换为颜色Col。

  为了满足墨墨的要求,你知道你需要干什么了吗?

输入格式:

  第1行两个整数N,M,分别代表初始画笔的数量以及墨墨会做的事情的个数。

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

  第2行N个整数,分别代表初始画笔排中第i支画笔的颜色。

  第3行到第2+M行,每行分别代表墨墨会做的一件事情,格式见题干部分。

输出格式:

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

输入样例: 

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

输出样例: 

 4
 4
 3
 4

题解: 

  分块。

  last[i]表示i这种颜色上次出现的位置,b[i]表示i这个位置的颜色上次出现的位置,显然b[i]=last[color[i]]。

  修改时候要这个区间全部的last(先清空)与b修改,然后重新分块排序。

  然后询问在l到r有多少个数b[i]<l(因为当前颜色上次出现的位置不在区间内就说明当前颜色第一次出现,统计答案)

  不在块中的暴力,在块中的排序然后二分即可。

 1 #include<iostream>
 2 #include<cstdlib>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<algorithm>
 6 #include<cmath>
 7 using namespace std;
 8 int n,Q,m,blo;
 9 int a[1000005],b[1000005],bl[1000005],c[1000005],last[1000005];
10 inline void reset(int x){
11     int l=(x-1)*blo+1,r=x*blo;
12     for(int i=l;i<=r;i++){
13         c[i]=b[i];
14     }
15     sort(c+l,c+r+1);
16 }
17 inline void update(int x,int k){
18     a[x]=k;
19     for(int i=1;i<=n;i++)    last[i]=0;
20     for(int i=1;i<=n;i++){
21         int t=b[i];
22         b[i]=last[a[i]];
23         last[a[i]]=i;
24         if(b[i]!=t)    reset(bl[i]);
25     }
26 }
27 inline int find(int x,int v){
28     return lower_bound(c+(x-1)*blo+1,c+x*blo+1,v)-c-((x-1)*blo+1);
29 }
30 inline int query(int x,int y){
31     int ans=0;
32     if(bl[x]==bl[y]){
33         for(int i=x;i<=y;i++)
34             if(b[i]<x)    ans++;
35         return ans;
36     }
37     else{
38         for(int i=x;i<=bl[x]*blo;i++)
39             if(b[i]<x)    ans++;
40         for(int i=(bl[y]-1)*blo+1;i<=y;i++)
41             if(b[i]<x)    ans++;
42     }
43     for(int i=bl[x]+1;i<=bl[y]-1;i++)
44         ans+=find(i,x);
45     return ans;
46 }
47 int main(){
48     int x,y;
49     char ch[5];
50     scanf("%d%d",&n,&Q);
51     for(int i=1;i<=n;i++)    scanf("%d",&a[i]);
52     blo=(int)sqrt(n);
53     if(n%blo)    m=n/blo+1;
54     else    m=n/blo;
55     for(int i=1;i<=n;i++){
56         bl[i]=(i-1)/blo+1;
57         b[i]=last[a[i]];
58         last[a[i]]=i;
59     }
60     for(int i=1;i<=m;i++)    reset(i);
61     while(Q--){
62         scanf("%s%d%d",ch,&x,&y);
63         if(ch[0]=='R')    update(x,y);
64         else    printf("%d\n",query(x,y));
65     }
66     return 0;
67 }

 

posted @ 2017-12-06 22:34  LittleOrange  阅读(244)  评论(0编辑  收藏  举报