zoukankan      html  css  js  c++  java
  • BZOJ2453:维护队列——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=2453

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

    ——————————————————————————————————————

    一种单点修改的分块。

    我们维护:

    1.sum[i][j]:前j块i元素出现次数。

    2.ans[i][j]:i~j块的颜色种数。

    修改的时候我们显然sum数组可以O(sqrtN)修改成功,而ans数组通过暴力也可以在O(N/4)的复杂度中修改成功。

    (实现方法看代码吧……)

    剩下的查询就比较简单了(可能是分块分多的错觉)

    #include<cstdio>
    #include<queue>
    #include<cctype>
    #include<cstring>
    #include<cmath>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int N=10010;
    const int SQRTN=110;
    const int M=11010;
    const int INF=2147483647;
    inline int read(){
        int X=0,w=0;char ch=0;
        while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
        while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    struct question{
        char op[10];
        int l,r;
    }q[N];
    int n,m,lim,s,cnt,a[N],b[M],bl[SQRTN],br[SQRTN];
    int sum[M][SQRTN],ans[SQRTN][SQRTN];
    bool vis[M];
    inline void initLSH(){
        sort(b+1,b+lim+1);
        lim=unique(b+1,b+lim+1)-b-1;
        for(int i=1;i<=n;i++){
        a[i]=lower_bound(b+1,b+lim+1,a[i])-b;
        }
        return;
    }
    inline int LSH(int x){return lower_bound(b+1,b+lim+1,x)-b;}
    inline void intoblock(){
        for(int i=1;i<=n;i++){
            if(i%s==1){br[cnt]=i-1;bl[++cnt]=i;}
        }
        br[cnt]=n;bl[cnt+1]=n+1;
        return;
    }
    inline void init(){
        for(int i=1;i<=cnt;i++){
        for(int j=1;j<=lim;j++)sum[j][i]=sum[j][i-1];
            for(int j=bl[i];j<=br[i];j++){
                sum[a[j]][i]++;
            }
        }
        for(int i=1;i<=cnt;i++){
            for(int j=i;j<=cnt;j++){
            ans[i][j]=ans[i][j-1];
            for(int k=bl[j];k<=br[j];k++)vis[a[k]]=0;
            for(int k=bl[j];k<=br[j];k++){
            int t=a[k];
            if(!vis[t]){
                int c=sum[t][j-1]-sum[t][i-1];
                if(!c)ans[i][j]++;
                vis[t]=1;
            }
            }
            }
        }
        return;
    }
    inline void modify(int x,int c){
        if(a[x]==c)return;
        int now=(x-1)/s+1;
        int old=a[x];
        a[x]=c;
        int nw=a[x];
        for(int i=1;i<=now;i++){
            for(int j=now;j<=cnt;j++){
            if(sum[old][j]-sum[old][i-1]==1)ans[i][j]--;
            if(sum[nw][j]-sum[nw][i-1]==0)ans[i][j]++;
            }
        }
        for(int i=now;i<=cnt;i++)sum[old][i]--,sum[nw][i]++;
        return;
    }
    inline int query(int l,int r){
        int cur=0;
        if(r-l+1<=2*s){
        for(int i=l;i<=r;i++)vis[a[i]]=0;
        for(int i=l;i<=r;i++){
            int t=a[i];
            if(!vis[t]){
            cur++;
            vis[t]=1;
            }
        }
            return cur;
        }
        int L=(l-1)/s+1,R=(r-1)/s+1;
        cur+=ans[L+1][R-1];
        for(int i=l;i<=br[L];i++)vis[a[i]]=0;
        for(int i=bl[R];i<=r;i++)vis[a[i]]=0;
        for(int i=l;i<=br[L];i++){
        if(!vis[a[i]]){
            int c=sum[a[i]][R-1]-sum[a[i]][L];
            if(!c)cur++;
            vis[a[i]]=1;
        }
        }
        for(int i=bl[R];i<=r;i++){
        if(!vis[a[i]]){
            int c=sum[a[i]][R-1]-sum[a[i]][L];
            if(!c)cur++;
            vis[a[i]]=1;
        }
        }
        return cur;
    }
    int main(){
        n=read();m=read();s=sqrt(n);
        for(int i=1;i<=n;i++)a[i]=b[++lim]=read();
        for(int i=1;i<=m;i++){
        cin>>q[i].op;
        q[i].l=read(),q[i].r=read();
        if(q[i].op[0]=='R')b[++lim]=q[i].r;
        }
        initLSH();
        intoblock();
        init();
        for(int i=1;i<=m;i++){
        if(q[i].op[0]=='R')modify(q[i].l,LSH(q[i].r));
        else printf("%d
    ",query(q[i].l,q[i].r));
        }
        return 0;
    }
  • 相关阅读:
    Penetration Test
    Penetration Test
    Penetration Test
    Penetration Test
    Penetration Test
    Penetration Test
    Penetration Test
    Java编程入门(图片)
    第七章:Java基础类库
    第六章:多线程综合案例
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/8183685.html
Copyright © 2011-2022 走看看