[bzoj2120]数颜色

来自FallDream的博客,未经允许,请勿转载,谢谢


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

n,m<=10000 修改操作最多1000

貌似是一道暴力都能过的题...233

正解是带修改的莫队,在莫队的基础上,加入修改操作。具体实现就是按照左右端点所在的块排序,左右端点在相同块的按照时间排序,然后在做一个询问的时候把时间修正一下,撤销多做的操作,时间太早就再改一改啥的。这样的话我们把块的数量设成$n^{\frac{1}{3}}$最优,复杂度上限$n^{\frac{5}{3}}$

但是其实可以直接在线做,还是分成$k=n^{\frac{1}{3}}$块,每一个块对开一个数组预处理出答案,预处理$k^{2}n$,然后每次修改直接修改所有包含它的块,复杂度$k^{2}q$,查询找到最接近的块对,然后暴力改剩下的,最后再还原回去,复杂度最大$\frac{nq}{k}$。它的空间比较蛋疼....但是如果修改操作比较多或者强制在线,就能体现它的优势啦。

带修改莫队

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define MK 20
#define MN 11000
using namespace std;
inline int read()
{
    int x = 0 , f = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x * f;
}

int n,m,s[MN+5],L=1,R=1,T=0,kind=1,f[1000005],cnt1=0,cnt2=0,size,pos[MN+5],l[MN+5],Ans[MN+5];
struct ques{
    int last,x,y,lb,rb,time;
    bool operator<(const ques&b)const{b.lb==lb?(b.rb==rb?(time<b.time):rb<b.rb):lb<b.lb;}
}q[MN+5];
struct renew{int x,y,last;}r[MN+5];
char op[15];

inline void Change(int x,int y)
{
    if(L<=x&&x<=R)
    {
        if(!--f[s[x]]) --kind;
        if((++f[y])==1) ++kind; 
    }
    s[x]=y;
}

int main()
{
    n=read();m=read();
    for(int i=1;i<=n;i++) s[i]=l[i]=read();
    size=max((n+MK-1)/MK,1);
    for(int i=1;i<=m;i++)
    {
        scanf("%s",op+1);
        if(op[1]=='Q')
        {
            q[++cnt1].x=read();q[cnt1].y=read();
            q[cnt1].lb=(q[cnt1].x-1)/size+1;
            q[cnt1].rb=(q[cnt1].y-1)/size+1;
            q[cnt1].time=cnt1;q[cnt1].last=cnt2;
        }
        else
        {
            r[++cnt2].x=read();r[cnt2].y=read();
            r[cnt2].last=l[r[cnt2].x];
            l[r[cnt2].x]=r[cnt2].y;
        }
    }
    sort(q+1,q+cnt1+1);
    f[s[1]]=1;
    for(int i=1;i<=cnt1;i++)
    {
        while(L<q[i].x) if(!--f[s[L++]])   --kind;
        while(L>q[i].x) if(++f[s[--L]]==1) ++kind;
        while(R>q[i].y) if(!--f[s[R--]])   --kind;
        while(R<q[i].y) if(++f[s[++R]]==1) ++kind;
        while(T<q[i].last) ++T,Change(r[T].x,r[T].y);
        while(T>q[i].last) Change(r[T].x,r[T].last),--T;
        Ans[q[i].time]=kind;        
    }
    for(int i=1;i<=cnt1;i++) printf("%d\n",Ans[i]);
    return 0;
}

分块 

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define MK 8
#define MN 11000
char B[1<<23],*S=B;
#define getchar() (*S++) 
using namespace std;
inline int read()
{
    int x = 0 , f = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x * f;
}

int n,m,s[MN+5],l[MN*2+5],kind[MK+1][MK+1],tot,size,mx,f[MK+1][MK+1][MN+2],pos[MN+5];
struct ques{int kind,x,y;}q[MN+5];
char op;

int main()
{
    fread(B,1,1<<23,stdin);
    tot=n=read();m=read();
    register int i,j,k;
    for(i=1;i<=n;i++) s[i]=l[i]=read();
    for(i=1;i<=m;i++)
    {
        do op=getchar(); while(op!='Q'&&op!='R');q[i].x=read();q[i].y=read();
        if(op=='Q') q[i].kind=2;
        else q[i].kind=1,l[++tot]=q[i].y;
    }
    sort(l+1,l+tot+1);int sz=1;
    for(i=2;i<=tot;i++) 
        if(l[i]!=l[i-1]) l[++sz]=l[i];tot=sz;
    for(i=1;i<=n;i++)s[i]=lower_bound(l+1,l+tot+1,s[i])-l;
    size=(n+MK-1)/MK;mx=(n+size-1)/size;
    for(i=1;i<=mx;i++)        
        for(j=(i-1)*size+1;j<=n;j++)
            for(k=(j-1)/size+1;k<=mx;k++)
                if(++f[i][k][s[j]]==1) ++kind[i][k];    
    for(i=1;i<=m;i++)
    {
        if(q[i].kind==1)
        {
            q[i].y=lower_bound(l+1,l+tot+1,q[i].y)-l;
            int pos=(q[i].x-1)/size+1;
            for(int j=1;j<=pos;j++)
                for(int k=pos;k<=mx;k++)
                {
                    if(!--f[j][k][s[q[i].x]]) kind[j][k]--;
                    if(++f[j][k][q[i].y]==1)  kind[j][k]++;
                } 
            s[q[i].x]=q[i].y;
        } 
        else
        {
            int a=max(1,(q[i].x+size/2)/size),b=max(1,(q[i].y+size/2)/size);
            int st=(a-1)*size+1,ed=b*size;
            if(q[i].x>st)
            {
                for(j=st;j<q[i].x;j++)
                    if(!--f[a][b][s[j]]) 
                        --kind[a][b];
            }
            else
                for(j=q[i].x;j<st;j++)
                    if(++f[a][b][s[j]]==1) ++kind[a][b];
            if(q[i].y<ed)
            {
                for(j=q[i].y+1;j<=ed;j++)
                    if(!--f[a][b][s[j]]) --kind[a][b];
            }
            else
                for(j=q[i].y;j>ed;j--)
                    if(++f[a][b][s[j]]==1) ++kind[a][b]; 
            printf("%d\n",kind[a][b]);
            if(q[i].x>st)
            {
                for(j=st;j<q[i].x;j++)
                    if(++f[a][b][s[j]]==1) ++kind[a][b];
            }
            else
                for(j=q[i].x;j<st;j++)
                    if(!--f[a][b][s[j]]) --kind[a][b];
            if(q[i].y<ed)
            { 
                for(j=q[i].y+1;j<=ed;j++)
                    if(++f[a][b][s[j]]==1) ++kind[a][b];
            } 
            else
                for(j=q[i].y;j>ed;j--)
                    if(!--f[a][b][s[j]]) --kind[a][b];    
        }
    }
    return 0;
}

 

posted @ 2017-04-07 09:55  FallDream  阅读(179)  评论(0编辑  收藏  举报