[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);
		}
	}
}


posted @ 2017-09-12 17:20  Drenight  阅读(114)  评论(0编辑  收藏  举报