Almost Union-Find UVA - 11987 (带删除的并查集)

Almost Union-Find

 UVA - 11987 

这题的重点在于一些点会被删除,但是我们知道,如果不是根节点的还好,一旦删除根节点,该并查集的结构就被严重破坏了,因此我们选择设置一个虚点,他不存在,也不贡献点的数量,也不贡献值,仅仅是存在于那里为我们来维持结构。

为了达到这个目的,我们为每个点设定一个id值每当这个点经历了一次删除操作,我们就为他更换一个新的ip。再检索时就用这个新的ID进行检索,而旧的ID就放在那里储存和维持原来的结构。特别需要注意的是,我们总是通过点来确定,我们到底是要搜索哪个id而在后续的搜索和合并都使用id值来进行合并。即信息的储存仅与id有关,而id与点有关,但点与信息无关。

具体细节见代码:

#include<iostream>
#include<cstdio>
#define int long long
using namespace std;
const int size=1e6+5;
int tot;
int fa[size],id[size],cnt[size],sum[size];
void init(int n)
{
	tot=n+1;
	for(int i=1;i<=n;i++)
	{
		cnt[i]=1;
		sum[i]=i;
		fa[i]=i;
		id[i]=i;
	}
}
int find(int x)
{
	return x==fa[x]?x:fa[x]=find(fa[x]);
}
void merge(int x,int y)
{
	int fx=find(id[x]),fy=find(id[y]);
	if(fx==fy) return;
	cnt[fy]+=cnt[fx];
	sum[fy]+=sum[fx];
	cnt[fx]=0,sum[fx]=0;
	fa[fx]=fy;
}
void move(int x,int y)
{
	int fx=find(id[x]),fy=find(id[y]);
	id[x]=++tot;
	fa[tot]=fy;
	sum[fy]+=x;
	cnt[fy]++;
	sum[fx]-=x;
	cnt[fx]--;	
}
int32_t main()
{
	int n,k;
	while(~scanf("%lld%lld",&n,&k))
	{
		init(n);
		while(k--)
		{
			int op;
			scanf("%lld",&op);
			if(op==1)
			{
				int a,b;
				scanf("%lld%lld",&a,&b);
				merge(a,b);
			}
			if(op==2)
			{
				int a,b;
				scanf("%lld%lld",&a,&b);
				move(a,b);
			}
			if(op==3)
			{
				int x;
				scanf("%lld",&x);
				int fx=find(id[x]);
				cout<<cnt[fx]<<' '<<sum[fx]<<endl;
			}
		}
	}
}

 

posted @ 2018-08-06 19:49  Fly_White  阅读(156)  评论(0编辑  收藏  举报