BZOJ 2453: 维护队列&&BZOJ 2120 数颜色 分块

来源:互联网 发布:fifa online数据库 编辑:程序博客网 时间:2024/05/17 02:22

2453: 维护队列

Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 1147 Solved: 533
[Submit][Status][Discuss]

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的整数表示。

2120: 数颜色

Time Limit: 6 Sec Memory Limit: 259 MB
Submit: 5457 Solved: 2180
[Submit][Status][Discuss]

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

Sample Output

4

4

3

4

HINT

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

2016.3.2新加数据两组by Nano_Ape

这道题再不过我都要崩溃了。
(我发现A了2453之后2120都不用改代码的 就放在一起发了)
题解:其实这道题应该是可以用可持久化线段树来做的,但需要修改,所以我们就套一个树状数组。然而太麻烦啦。(毕竟我比较弱)
考虑分块。
记一个数上次出现的位置为这个数的前驱。对于询问一个区间[l,r]内有多少个不同的数,即询问有多少前驱

#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#include<ctime>using namespace std;const int N = 1000010;const int M = 10010;int n,m;int a[M],b[N];int blo;int bl[M];int Pre[N],col[N];struct node{    int l,r;}B[M];void fenkuai(int i){    int x=B[i].l,y=B[i].r+1;    for(register int i=x;i<y;i++) Pre[i]=b[i];    sort(Pre+x,Pre+y);}int find(int x,int d){    int l=B[x].l,r=B[x].r;    while(l<=r){        int mid=l+r>>1;        if(Pre[mid]<d) l=mid+1;        else r=mid-1;    }    return l-B[x].l;}int query(int l,int r){    int ans=0;    if(bl[l]==bl[r]){        for(register int i=l;i<=r;i++) if(b[i]<l) ans++;        return ans;    }    for(register int i=l;i<=B[bl[l]].r;i++) if(b[i]<l) ans++;    for(register int i=B[bl[r]].l;i<=r;i++) if(b[i]<l) ans++;    for(register int i=bl[l]+1;i<bl[r];i++){        ans+=find(i,l);    }    return ans;}#define ms(x,y) memset(x,y,sizeof(x))void modify(int x,int d){    a[x]=d;    //ms(col,0); memset 会TLE!!!!     for(register int i=1;i<=n;i++) col[a[i]]=0;    for(register int i=1;i<=n;i++){        int t=b[i];        b[i]=col[a[i]],col[a[i]]=i;        if(t!=b[i]) fenkuai(bl[i]);    }}int main(){    scanf("%d%d",&n,&m);    //blo=sqrt(n);    blo=int(sqrt(n)+log(2*n)/log(2));    //这样分块会快一点    for(register int i=1;i<=n;i++){        scanf("%d",&a[i]);        bl[i]=(i-1)/blo+1;        if(bl[i]!=bl[i-1]) B[bl[i-1]].r=i-1,B[bl[i]].l=i;        b[i]=col[a[i]],col[a[i]]=i;    }    B[bl[n]].r=n;    for(register int i=1;i<=bl[n];i++){        fenkuai(i);}    while(m--){        char s[10];scanf("%s",s);        if(s[0]=='Q'){            int l,r;            scanf("%d%d",&l,&r);            if(l>r) swap(l,r);            printf("%d\n",query(l,r));        }        else{            int x,d;            scanf("%d%d",&x,&d);            modify(x,d);        }    }    return 0;}