洛谷 P3144 [USACO16OPEN] Closing the Farm S(并查集+逆向思维)

题目描述

FJ 和他的奶牛们正在计划离开小镇做一次长的旅行,同时 FJ 想临时地关掉他的农场以节省一些金钱。

这个农场一共有被用 M 条双向道路连接的 N 个谷仓(1≤N,M≤3000)。为了关闭整个农场,FJ 计划每一次关闭掉一个谷仓。当一个谷仓被关闭了,所有的连接到这个谷仓的道路都会被关闭,而且再也不能够被使用。

FJ 现在正感兴趣于知道在每一个时间(这里的“时间”指在每一次关闭谷仓之前的时间)时他的农场是否是“全连通的”——也就是说从任意的一个开着的谷仓开始,能够到达另外的一个谷仓。注意自从某一个时间之后,可能整个农场都开始不会是“全连通的”。

输入格式

输入第一行两个整数 N,M。

接下来 M 行,每行两个整数 u,v(1≤u,v≤N),描述一条连接 u,v 两个农场的路。

最后 N 行每行一个整数,表示第 i 个被关闭的农场编号。

输出格式

输出 N 行,每行包含 YES 或 NO,表示某个时刻农场是否是全连通的。

第一行输出最初的状态,第 i 行(2≤i≤N)输出第 i−1 个农场被关闭后的状态。

输入输出样例

输入 

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

输出 

YES
NO
YES
YES
#include
using namespace std;
typedef long long ll;
const ll M=4e4+10;
const ll N=3e3+10;
int n,m,s,t;
int fa[N];
vector v[N];
int order[N];
int vis[N];
int res[N];
int find(int x)
{
	return fa[x]==x?x:fa[x]=find(fa[x]);
}
void merge(int x,int y)
{
	int fx=find(x);
	int fy=find(y);
	if(fx!=fy)
	fa[fx]=fy;
}
int cal()
{
	int cnt=0;
	for(int i=1;i<=n;i++)
	{
		if(vis[i])
		{
			cnt+=(find(i)==i);
		}
	}
	return cnt;
}
void solve()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	fa[i]=i;
	for(int i=1;i<=m;i++)
	{
		int x,y;
		cin>>x>>y;
		v[x].push_back(y);
		v[y].push_back(x);
	}
	for(int i=1;i<=n;i++)
	{
		int x;
		cin>>x;
		order[i]=x;
		vis[x]=0;
	}
	for(int i=n;i>=1;i--)
	{
		int o=order[i];
		vis[o]=1;
		for(auto it:v[o])
		{
			if(vis[it])
			merge(o,it);
		}
		res[i]=cal();
	}
	for(int i=1;i<=n;i++)
	{
		if(res[i]==1)
		cout<<"YES"<>t;
	while(t--)
	{	
		solve();
	}
	return 0;
}

你可能感兴趣的:(算法,c++)