西北大学2019年春季校赛 NE的挑战II 带删除并查集

题目描述

NE给你了一个挑战,来测试你的实力:

他查阅了历史上势力之间的关系变动,并想推演整个英仙座的势力情况,你能帮他完成这个任务吗?

NE会不断进行如下五种操作,格式如下:

1 A B    势力A和势力B进行结盟,注意:当A和B成为盟友时,A、B以及A、B的所有盟友之间都会成为盟军

2 A B    势力A和当前所有的盟军势力取消盟军关系,并和势力B成为盟军

3 A     查询势力A的盟军的数量

4 A B   查询势力A和势力B是否为盟军

5 A B   势力A和势力B出现了隐藏的历仇恨,势力间的仇恨并不影响势力的行为,但是会一直存在。

在进行完所有的推演之后,最后NE想选择一个联盟加入,同时这个联盟的内部势力之间不存在隐藏的仇恨。

NE并不在乎他到底加入了具体哪个联盟,他只想知道他加入的联盟最大能有多大。

输入描述

输入第一行包含两个数字n,m分别代表势力数和操作数1≤n,m≤〖10〗^6

接下来m行,每行代表一次操作,5种操作的格式如上所述。

输出描述

对于操作3、4,每次输出一行,即为所求的答案。

特别地,对于操作4,若A,B为盟军,输出"Yes \"",否则输出"No"。

结束所有操作之后,输出一行,包含一个整数,即为最大的联盟大小,如果不存在这样的联盟,则输出-1。

样例输入 1 

5 5 
1 2 3 
2 3 4 
3 2
4 4 2
5 3 4 

样例输出 1

0
No
1

主要是操作2   :理解下面例子就可以了

例子:食品店要给顾客甲派送食物food装在箱子box里,box有个挂钩(挂钩就相当于连接父节点的边)。food[]存储箱子编号,box[]存父节点。

food有很多,把要送的归在一类后。顾客甲打电话退订了某些。

如下图,food[2]=2.编为2的food它的箱子box编号是2

box[3]=3;编号为3的箱子box它的挂钩挂在自己上(它的父节点是它自己)。

 

建立如下并查集树。box[3]=2;

 

然后顾客甲打电话要退订编号为4,6的food。

接下来我们只需要把编号为4的food拿走,用编号为n++(7)的箱子装起来。

food[4]=7;

box[7]=[7];

编号为4的箱子依然留在那里,这样就不影响编号4的box后面挂的箱子的根节点就不会丧失。

拿走6同理。

food[6]=8;

box[8]=8;

接下来又有一顾客乙要走了4,6.

box[food[6]]=food[4];\\把编号为6的food它所在的箱子8的挂钩挂到编号为4的food它所在的箱子7上。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<stack>
#include<cstdlib>
#include<deque> 
#include<bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int>P;
const int len=2e6+5;
const double pi=acos(-1.0);
const ll mod=1e8+7;
int food[len],box[len],num[len]; 
int tot;
vector<P>ve;
int find(int x)
{
	if(x==box[x])return x;
	return box[x]=find(box[x]);
}
void mer(int x,int y)
{
	x=find(food[x]);
	y=find(food[y]);
	if(x==y)return ;
	num[x]+=num[y];
	box[y]=x;
	num[y]=0;
}
void update(int x,int y)
{
	num[find(food[x])]--;
	food[x]=++tot;
	box[tot]=tot;
	num[tot]=1;
	mer(x,y);
}
int main()
{
	int n,m;
	cin>>n>>m;
	tot=n;
	for(int i=1;i<=n;++i)
	{
		box[i]=i;
		food[i]=i;
		num[i]=1;
	}
	for(int i=1;i<=m;++i)
	{
		int op,x,y;
		scanf("%d%d",&op,&x);
		if(op!=3)scanf("%d",&y);
		if(op==1)mer(x,y);
		else if(op==2)update(x,y);
		else if(op==3)printf("%d\n",num[find(food[x])]-1);
		else if(op==4)find(food[x])==find(food[y])?puts("Yes"):puts("No");
		else ve.push_back({x,y}); 
	}
	int ans=-1;
	for(int i=0;i<ve.size();++i)
		if(find(food[ve[i].first])==find(food[ve[i].second]))num[find(food[ve[i].second])]=-1;
	for(int i=1;i<=n;++i)
		ans=max(ans,num[find(food[i])]);
	cout<<ans<<endl;
}


 

猜你喜欢

转载自blog.csdn.net/hutwuguangrong/article/details/88661747