• [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
    ",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
    ",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;
    }
  • 相关阅读:
    2021/9/23(桶排序+基数排序 结束排序)
    【转】十大经典排序算法(动画演示)
    如何测试代码执行时间
    图解排序算法之归并排序(转)
    TED演讲:拖延症人群的内心世界
    IntelliJ IDEA入门
    支付宝支付入门
    Spring Cloud 入门
    软件设计模式类型介绍
    《小狗钱钱2》读书笔记
  • 原文地址:https://www.cnblogs.com/FallDream/p/bzoj2120.html
Copyright © 2020-2023  润新知