BZOJ1483HNOI2009梦幻布丁

Posted Melacau----论一个蒟蒻的自我修养

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ1483HNOI2009梦幻布丁相关的知识,希望对你有一定的参考价值。

题意: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\n",ans);
    }
}
int main(){init();solve();return 0;}

 

以上是关于BZOJ1483HNOI2009梦幻布丁的主要内容,如果未能解决你的问题,请参考以下文章

bzoj1483[HNOI2009]梦幻布丁 set

bzoj 1483: [HNOI2009]梦幻布丁

BZOJ1483[HNOI2009]梦幻布丁 链表+启发式合并

bzoj 1483: [HNOI2009]梦幻布丁 启发式合并vector

Bzoj1483 [HNOI2009]梦幻布丁

BZOJ 1483:[HNOI2009]梦幻布丁(链表+启发式合并)