[BZOJ2120]数颜色(带修改莫队)

来源:互联网 发布:优化国税环境建设 编辑:程序博客网 时间:2024/05/18 19:22

题目描述

传送门

题解

和BZOJ2453相同,在这里可以看到分块的做法
而这道题同时又是一道带修莫队裸题
带修莫队大体方法如下:
1、将修改询问离线并分开,记录每一个修改之前最近的一次询问的编号
2、分块之后将区间排序,关键字为:左端点块的编号、右端点块的编号、记录的最近一次修改的编号
3、在查询每一次询问之前,判断当前做过的修改是否恰好是这次询问需要的修改,如果不够将其修改,修改多了的话恢复回去,注意如果修改的位置在前一个询问的区间内要更新答案
4、转移询问和普通莫队相同

代码

#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>#include<cmath>using namespace std;#define N 10005int n,m,cq,cc,block,now,ans;struct data{int x,y,t,id,ans;}q[N],ch[N];int c[N],num[N],last[N],cnt[N*100];int cmp(data a,data b){    return num[a.x]<num[b.x]||(num[a.x]==num[b.x]&&num[a.y]<num[b.y])||(num[a.x]==num[b.x]&&num[a.y]==num[b.y]&&a.t<b.t);}void modui(int x,int y,int val){    for (int i=x;i<=y;++i)    {        if (val==1)        {            if (!cnt[c[i]]) ++ans;            ++cnt[c[i]];        }        else        {            --cnt[c[i]];            if (!cnt[c[i]]) --ans;        }    }}int main(){    scanf("%d%d",&n,&m);    for (int i=1;i<=n;++i) scanf("%d",&c[i]);    block=sqrt(n);    for (int i=1;i<=n;++i) num[i]=(i-1)/block+1;    for (int i=1;i<=m;++i)    {        char opt=getchar();        while (opt!='R'&&opt!='Q') opt=getchar();        if (opt=='R')        {            ++cc;            scanf("%d %d",&ch[cc].x,&ch[cc].y);        }        else        {            ++cq;q[cq].id=cq;            scanf("%d %d",&q[cq].x,&q[cq].y);            q[cq].t=cc;        }    }    sort(q+1,q+cq+1,cmp);now=q[1].t;    for (int i=1;i<=q[1].t;++i)    {        last[i]=c[ch[i].x];        c[ch[i].x]=ch[i].y;    }    modui(q[1].x,q[1].y,1);q[q[1].id].ans=ans;    for (int i=2;i<=cq;++i)    {        if (now<q[i].t)            for (int j=now+1;j<=q[i].t;++j)            {                if (ch[j].x>=q[i-1].x&&ch[j].x<=q[i-1].y)                {                    --cnt[c[ch[j].x]];                    if (!cnt[c[ch[j].x]]) --ans;                    if (!cnt[ch[j].y]) ++ans;                    ++cnt[ch[j].y];                }                last[j]=c[ch[j].x];                c[ch[j].x]=ch[j].y;            }        else if (now>q[i].t)            for (int j=now;j>q[i].t;--j)            {                if (ch[j].x>=q[i-1].x&&ch[j].x<=q[i-1].y)                {                    --cnt[c[ch[j].x]];                    if (!cnt[c[ch[j].x]]) --ans;                    if (!cnt[last[j]]) ++ans;                    ++cnt[last[j]];                }                c[ch[j].x]=last[j];            }        now=q[i].t;        if (q[i].x>q[i-1].x) modui(q[i-1].x,q[i].x-1,-1);        else modui(q[i].x,q[i-1].x-1,1);        if (q[i].y>q[i-1].y) modui(q[i-1].y+1,q[i].y,1);        else modui(q[i].y+1,q[i-1].y,-1);        q[q[i].id].ans=ans;    }    for (int i=1;i<=cq;++i) printf("%d\n",q[i].ans);}
0 0
原创粉丝点击