题目链接:https://www.luogu.com.cn/problem/P3144
- 起初有n个谷仓有m条路径,问依次关闭n个谷仓之后,农场的联通情况如何,谷仓关闭之后相应的路径也随着消失
- 我们可以倒着思考,转换为谷仓从无到有的过程,依次添加谷仓,当联通块数为1时,表明联通,否则为分散
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define sc(a) scanf("%d", &a)
#define sc2(a, b) scanf("%d%d", &a, &b)
#define ss(a) scanf("%s", a)
#define mem(a, b) memset(a, b, sizeof(a))
#define PII pair<int, int>
using namespace std;
const int INF = 0x3f3f3f3f;
const double pi = acos(-1.0), eps = 1e-8;
const int N = 2e5 + 5;
int pre[N], order[N], vis[N], p[N];
int find(int a)
{
if (a == pre[a])
return a;
return pre[a] = find(pre[a]);//路径压缩
}
vector<int> v[N];
int main()
{
int n, m;
sc2(n, m);
for (int i = 1; i <= m; i++)
{
int x, y;
sc2(x, y);
v[x].push_back(y);
v[y].push_back(x);
}
for (int i = 1; i <= n; i++)
{
int x;
sc(x);
order[i] = x;//记录关闭顺序
pre[i] = i;//初始化并查集
vis[i] = 0;//标记是否存在
}
int ans = 0;//连通块数
for (int i = n; i >= 1; i--)//倒着看,依次添加谷仓
{
int t = order[i];
vis[t] = 1;
ans++;//由于加进来一个孤立的点,连通块个数加一
for (auto j : v[t])//遍历与这谷仓向连接的其他谷仓
{
if (vis[j])//如果也存在的话,将其联通
{
int uu = find(t), vv = find(j);
if (uu != vv)//如果本身不连通的话,连通块个数就减1
{
ans--;
pre[uu] = vv;
}
}
}
if (ans == 1)//如果连通块个数为1,说明整个农场还是联通的
p[i] = 1;
else//否则,农场是分散的
p[i] = 0;
}
for (int i = 1; i <= n; i++)//输出结果
{
if (p[i])
cout << "YES" << endl;
else
cout << "NO" << endl;
}
system("pause");
return 0;
}