P3144 [USACO16OPEN]关闭农场——离线,并查集

https://www.luogu.org/problem/P3144

 

每次关闭一个农场,农场之间有边相连,问每次关闭后开着的农场是否是一个连通块;

数据小,离线搞;

我们先记录删的顺序,然后倒着来,先将所有删去的点都标记,每次加点,再把所有没删的都加在一起,

in_class[i]==1表示这个点在农场里;

我们从一个删点的过程变成一个加点的过程;

因为在第n次点都删完了,所以一定是一个连通块(体积为0);

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=3010;
int n,m;
int father[maxn];
int xx[maxn],yy[maxn];
int getfather(int x)
{
    if(father[x]==x) return x;
    father[x]=getfather(father[x]);
    return father[x];
}
int in_class[maxn];
int delete_order[maxn];

void merge(int x,int y)
{
    int fx=getfather(x);
    int fy=getfather(y);
    if(father[fx]!=fy)
    {
        father[fx]=fy;
    }
}
int num_block[maxn];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&xx[i],&yy[i]);
    }
    for(int i=1;i<=n;i++)
    {
        int w;
        scanf("%d",&w);
        delete_order[i]=w;
        in_class[w]=0;
        father[i]=i;
    }
    for(int i=n;i>=1;i--)
    {
        in_class[delete_order[i]]=1;
        for(int j=1;j<=m;j++)
        {
            if(in_class[xx[j]]==1&&in_class[yy[j]]==1)
            {
                merge(xx[j],yy[j]);
            }
        }
        for(int j=1;j<=n;j++)
        {
            if(in_class[j]==1&&getfather(j)==j)
            {
                num_block[i]++;
            }
        }
    }
    for(int i=1;i<n;i++)
    {
        if(num_block[i]==1) printf("YES\n");
        else printf("NO\n");
    }
    printf("YES\n");
    return 0;
}

 

posted @ 2019-09-28 11:13  AiRomance  阅读(161)  评论(0编辑  收藏  举报