• 【BZOJ1483】【HNOI2009】梦幻布丁


    题意:n个连续的点,有若干种颜色,每个颜色会因为某些操作变为另一种颜色,动态查询颜色段数。

    解题思路:对每个颜色开一棵平衡树启发式合并应该是最裸的想法,但是我们有更优的!

    考虑对每个颜色利用链表储存它的集合,在合并两种颜色时可以很简单通过对比原节点位置的前后颜色来进行答案的更新,然后利用启发式合并进行保证合并效率即可。

    总复杂度: ( O( q log c ) ) / ( O (c) ) C表示颜色数。(目前是BZOJ Rank2 200ms)

    #include <stdio.h>
    #define MN 100005
    #define MC 1000005
    #define r register
    #define getchar() (S==TT&&(TT=(S=BB)+fread(BB,1,1<<15,stdin),TT==S)?EOF:*S++)
    char BB[1<<15],*S=BB,*TT=BB;
    inline int read(){
        r int x=0;r char c;
        for (;(c=getchar())<'0'||c>'9';);
        for (x=c-'0';(c=getchar())>='0'&&c<='9';x=(x<<3)+(x<<1)+c-'0');
        return x;
    }
    inline void swap(int &a,int &b){a^=b^=a^=b;}
    int rt[MC],nxt[MN],s[MC],col[MN],n,q,ans;
    inline void merge(int x,int y){
        if (s[x]>s[y]){swap(x,y);}
        for (r int i=rt[x]; i; i=nxt[i]){
            ans-=(col[i-1]==y)+(col[i+1]==y);
            if (!nxt[i]){nxt[i]=rt[y];break;}
        }for (r int i=rt[x]; i!=rt[y]; i=nxt[i]) col[i]=y;
        rt[y]=rt[x];s[y]+=s[x];s[x]=rt[x]=0; 
    }
    void init(){
        n=read(),q=read();ans=1;
        for (int i=1; i<=n; ++i) col[i]=read(),nxt[i]=rt[col[i]],rt[col[i]]=i;
        for (r int i=2; i<=n; ++i) if (col[i]!=col[i-1]) ++ans;
    }
    void solve(){
        while(q--){
            r int op=read();
            if (op==1){r int x=read(),y=read();if (x!=y) merge(x,y);}
            else printf("%d
    ",ans);
        }
    }
    int main(){init();solve();return 0;}
  • 相关阅读:
    Linux下增加User及添加sudo权限
    windows下的asp.net core开发及docker下的发布
    Linux下建立虚拟内存
    Github访问慢解决办法
    Uva 10061
    SYOJ 1001. Alphacode
    SRM144DIV1 Lottery
    SRM609 DIV2 950
    mysql 半同步
    mysql root用户不知到密码的情况下修改密码
  • 原文地址:https://www.cnblogs.com/Melacau/p/BZOJ1483.html
Copyright © 2020-2023  润新知