[HNOI2009]梦幻布丁

[HNOI2009]梦幻布丁

给每个颜色的点挂个链.按size启发式暴力合并.
如果一个联通的色块左边或者右边等于要变的颜色,那么色块总数减一.这样维护答案就好了.

#include<bits/stdc++.h>
using namespace std;
#define maxn 1000005
int head[maxn],nxt[maxn],n,m,ans,cor[maxn],sz[maxn],ori[maxn];
void merge(int &x,int &y)
{
    if(x==y)return;
    if(sz[x]>sz[y])swap(x,y);
    for(int i=head[x];i;i=nxt[i])
    {
        ans-=(cor[i-1]==y)+(cor[i+1]==y);
        if(!nxt[i]){nxt[i]=head[y],head[y]=head[x];break;}
    }
    for(int i=head[x];i;i=nxt[i])cor[i]=y;
    sz[y]+=sz[x];sz[x]=0;head[x]=0;
}
int main()
{
    cin>>n>>m;int ty,x,y;
    for(int i=1;i<=n;i++)
        scanf("%d",&cor[i]),nxt[i]=head[cor[i]],head[cor[i]]=i,sz[cor[i]]++;
    for(int i=1;i<=maxn-5;i++)ori[i]=i;
    ans=1;for(int i=2;i<=n;i++)if(cor[i]!=cor[i-1])ans++;
    for(int i=1;i<=m;i++)
    {
        scanf("%d",&ty);
        if(ty==1)scanf("%d%d",&x,&y),merge(ori[x],ori[y]);
        else printf("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/terribleterrible/p/9827462.html
今日推荐