BZOJ 1483 HNOI2009 梦幻布丁 链表+启发式合并

题目大意:给定n个布丁,每个布丁有一个颜色,多次将某种颜色的所有布丁变为另一种颜色,多次询问颜色段数

数据范围:n<=10W 颜色数<=100W

链表的启发式合并0.0 一直没写明白 其实就是开个链表记录每种颜色的位置,合并时撸一遍短的链看看两边是不是长链的颜色就行

不过交换比较麻烦0.0 要开个数组记录每个数字代表的真实颜色 交换时把数组的这两个位置也交换下就可以了

注意用过的垃圾不要留在原位 size合并掉就清零 head合并走了就弄成NULL 不然会挂 强迫症的福音啊

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 1001001
using namespace std;
struct abcd{
	abcd *next;
	int pos;
}*head[M];
int n,m,ans,a[M];
int f[M],size[M];
inline void Add(int x,int y)
{
	abcd *temp=new abcd;
	temp->pos=y;
	temp->next=head[x];
	head[x]=temp;
}
inline void Merge(int x,int y)
{
	abcd *temp;
	
	if(x==y)
		return ;
	
	if(size[f[x]]>size[f[y]])
		swap(f[x],f[y]);
	x=f[x];y=f[y];
	
	if(!head[x])
		return ;
	
	for(temp=head[x];temp;temp=temp->next)
	{
		if(a[temp->pos-1]==y) --ans;
		if(a[temp->pos+1]==y) --ans;
	}
	for(temp=head[x];temp;temp=temp->next)
		a[temp->pos]=y;
	for(temp=head[x];temp->next;temp=temp->next);
	
	temp->next=head[y];head[y]=head[x];head[x]=0x0;
	size[y]+=size[x];size[x]=0;
	
}
int main()
{
	int i,p,x,y;
	cin>>n>>m;
	for(i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		if(a[i]!=a[i-1])
			++ans;
		Add(a[i],i);
		f[a[i]]=a[i];
		size[a[i]]++;
	}
	for(i=1;i<=m;i++)
	{
		scanf("%d",&p);
		if(p==1)
		{
	 		scanf("%d%d",&x,&y);
	 		Merge(x,y);
		}
		else
			printf("%d\n",ans);
	}
}


你可能感兴趣的:(链表,bzoj,启发式合并,BZOJ1483)