[HNOI2009]梦幻布丁 启发式链表合并
因为启发式合并,所以我们强制用长链代表短链,遍历修改短链的所有节点
由于我们只存储了位置之间是同色的关系形成的链条,这些链条无颜色特征,所以我们把长链分配给新颜色
即一次swap操作,用fa[x]记录颜色x的在C数组中存储的真实颜色
其他部分就是水水细节啦。。
#include<bits/stdc++.h> #include<stdio.h> #include<algorithm> #include<queue> #include<string.h> #include<iostream> #include<math.h> using namespace std; #define ll long long const int maxn=1e6+7; const int inf=0x3f3f3f3f; #define FOR(n) for(int i=1;i<=n;i++) #define pb push_back int n,m,ans; int c[maxn],fa[maxn]; int size[maxn],head[maxn],nxt[maxn]; void merge(int x,int y){ for(int i=head[x];i;i=nxt[i]){ if(c[i-1]==y)ans--; if(c[i+1]==y)ans--; } for(int i=head[x];i;i=nxt[i]){ c[i]=y; if(!nxt[i]){ nxt[i]=head[y],head[y]=head[x];break; } } size[y]+=size[x];head[x]=size[x]=0; } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d",&c[i]); if(c[i]!=c[i-1])ans++; fa[c[i]]=c[i]; nxt[i]=head[c[i]],head[c[i]]=i; size[c[i]]++; } for(int op,x,y,i=1;i<=m;i++){ scanf("%d",&op); if(op==2)printf("%d\n",ans); else{ scanf("%d%d",&x,&y); // x染色为y if(size[fa[x]]>size[fa[y]])swap(fa[x],fa[y]); x=fa[x],y=fa[y]; if(x==y || size[x]==0)continue; merge(x,y); } } }