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; }