P3144 [USACO16OPEN]Closing the Farm S(并查集)

题目链接: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;
}

猜你喜欢

转载自blog.csdn.net/weixin_43911947/article/details/107708666
今日推荐