BZOJ 2120 数颜色——带修改的莫队算法

来源:互联网 发布:淘宝手机怎么网页版 编辑:程序博客网 时间:2024/05/16 06:42

2120: 数颜色

题目描述

墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会像你发布如下指令: 1、 Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔。 2、 R P Col 把第P支画笔替换为颜色Col。为了满足墨墨的要求,你知道你需要干什么了吗?

输入

第1行两个整数N,M,分别代表初始画笔的数量以及墨墨会做的事情的个数。第2行N个整数,分别代表初始画笔排中第i支画笔的颜色。第3行到第2+M行,每行分别代表墨墨会做的一件事情,格式见题干部分。

输出

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

解题思路

这题就是BZOJ1878的升级版(多了一个修改操作),我们知道1878可以用莫队解,这不就是裸的带修改的莫队算法吗。我们知道莫队算法的核心在于离线之后的排序,那么每个修改操作就看成一个时间点,并标记每次询问的时间,然后进行三关键字的排序就可以了,询问时多开一个time表示当前时间。

#include<cmath>#include<cstdio>#include<algorithm>using namespace std;const int maxn=10005,maxm=1000005;int n,m1,m2,h[maxn],a[maxn],m,last[maxn],ans[maxn],num[maxm],tot;struct jz{    int L,R,t,id;}q[maxn];struct jz1{    int last,x,y;}c[maxn];bool cmp(jz a,jz b){    if (h[a.L]==h[b.L]){        if (h[a.R]==h[b.R]) return a.t<b.t;        return h[a.R]<h[b.R];    }    return h[a.L]<h[b.L];}inline int _read(){    int num=0;char ch=getchar();    while (ch<'0'||ch>'9') ch=getchar();    while (ch>='0'&&ch<='9') num=num*10+ch-48,ch=getchar();    return num;}void move(int x,int y){    if (y==1&&num[a[x]]==0) tot++;    if (y==-1&&num[a[x]]==1) tot--;    num[a[x]]+=y;}void change(int x,int y,int L,int R){    if (x>=L&&x<=R){move(x,-1);a[x]=y;move(x,1);}    else a[x]=y;}int main(){    freopen("exam.in","r",stdin);    freopen("exam.out","w",stdout);    n=_read();m=_read();    for (int i=1;i<=n;i++) a[i]=last[i]=_read();    while (m--){        char ch=getchar();        while (ch!='Q'&&ch!='R') ch=getchar();        int x=_read(),y=_read();        if (ch=='R'){            c[++m2].x=x;c[m2].y=y;            c[m2].last=last[x];last[x]=y;        }else{            q[++m1].L=x;q[m1].R=y;            q[m1].id=m1;q[m1].t=m2;        }    }    int k=pow(n,(double)2/3);for (int i=1;i<=n;i++) h[i]=(i-1)/k+1;    sort(q+1,q+1+m1,cmp);    int L=1,R=1,t=0;move(1,1);    for (int i=1;i<=m1;i++){        while (t<q[i].t) change(c[t].x,c[++t].y,L,R);        while (t>q[i].t) change(c[t--].x,c[t].last,L,R);        while (L<q[i].L) move(L++,-1);        while (L>q[i].L) move(--L,1);        while (R>q[i].R) move(R--,-1);        while (R<q[i].R) move(++R,1);        ans[q[i].id]=tot;    }    for (int i=1;i<=m1;i++) printf("%d\n",ans[i]);    return 0;}
1 0
原创粉丝点击