[bzoj1483]:[HNOI2009]梦幻布丁

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


 

N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1,2,2,1的四个布丁一共有3段颜色.

n,m<=10^5 ai<=10^6

 

第一眼觉得可以平衡树+启发式合并

但是想了想直接启发式合并就行了  用链表链起来即可。

复杂度最坏nlogn

#include<iostream>
#include<cstdio>
#define rint register int
#define MN 100000
using namespace std;
inline int read()
{
    int x = 0; char ch = getchar();
    while(ch < '0' || ch > '9')  ch = getchar();
    while(ch >= '0' && ch <= '9')x = x * 10 + ch - '0',ch = getchar();
    return x;
}

int n,m,ans=1,a[MN+5],head[MN*10+5],s[MN*10+5],size[MN*10+5],cnt=0;
struct edge{int x,next;}e[MN*35+5];
inline void ins(int f,int t){e[++cnt]=(edge){t,head[f]};head[f]=cnt;}

inline void Merge(int x,int y)
{
    x=s[x];y=s[y];size[y]+=size[x];
    for(rint i=head[x];i;i=e[i].next)    
        ans-=(e[i].x!=1&&a[e[i].x-1]==y)+(e[i].x!=n&&a[e[i].x+1]==y);
    for(rint i=head[x];i;i=e[i].next)
        ins(y,e[i].x),a[e[i].x]=y;
    head[x]=size[x]=0;
}

int main()
{
    n=read();m=read();
    for(rint i=1;i<=n;++i) a[i]=read(),s[a[i]]=a[i];
    for(rint i=1;i<=n;++i) ++size[a[i]],ins(a[i],i),ans+=(i!=1&&a[i]!=a[i-1]);
    for(rint i=1;i<=m;++i)
    {
        int op=read();
        if(op==1) 
        {
            int x=read(),y=read();if(x==y) continue;
            if(size[s[x]]>size[s[y]]) swap(s[x],s[y]);
            Merge(x,y);s[x]=0;
        }
        else printf("%d\n",ans);
    }
    return 0;
}
posted @ 2017-05-16 13:57  FallDream  阅读(143)  评论(0编辑  收藏  举报