[USACO16OPEN]关闭农场Closing the Farm_Silver
题目描述
FJ和他的奶牛们正在计划离开小镇做一次长的旅行,同时FJ想临时地关掉他的农场以节省一些金钱。
这个农场一共有被用M条双向道路连接的N个谷仓(1<=N,M<=3000)。为了关闭整个农场,FJ 计划每一次关闭掉一个谷仓。当一个谷仓被关闭了,所有的连接到这个谷仓的道路都会被关闭,而且再也不能够被使用。
FJ现在正感兴趣于知道在每一个时间(这里的“时间”指在每一次关闭谷仓之后的时间)时他的农场是否是“全连通的”——也就是说从任意的一个开着的谷仓开始,能够到达另外的一个谷仓。注意自从某一个时间之后,可能整个农场都开始不会是“全连通的”。
输入输出样例
输入样例#1:
4 3 1 2 2 3 3 4 3 4 1 2
输出样例#1:
YES NO YES YES
反其道行之,我们离线模拟从空状态一个个加点
用并查集维护
每加入一个点,扫描与其相邻的点,如果是已开放的点,那么就合并
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 using namespace std; 5 struct Messi 6 { 7 int next,to; 8 }edge[400001]; 9 int head[200001],n,set[200001],m,order[200001],b[200001],ans[200001]; 10 void add(int u,int v,int num) 11 { 12 edge[num].next=head[u]; 13 head[u]=num; 14 edge[num].to=v; 15 } 16 int father(int x) 17 { 18 if (set[x]==x) return x; 19 else return set[x]=father(set[x]); 20 } 21 void merge(int x,int y) 22 {int p,q; 23 p=father(x); 24 q=father(y); 25 if (p!=q) 26 set[p]=q; 27 } 28 void check(int x) 29 {int i; 30 int cnt=0; 31 for (i=1;i<=n;i++) 32 { 33 if (cnt>=2) break; 34 if (set[i]==i&&b[i]) 35 cnt++; 36 } 37 if (cnt==1) ans[x]=1; 38 else ans[x]=0; 39 } 40 int main() 41 {int i,u,v,j; 42 43 cin>>n>>m; 44 for (i=1;i<=m;i++) 45 {scanf("%d%d",&u,&v); 46 add(u,v,i); 47 add(v,u,m+i); 48 } 49 for (i=1;i<=n;i++) 50 { 51 scanf("%d",&order[i]); 52 } 53 for (i=1;i<=n;i++) 54 set[i]=i; 55 for (i=n;i>=1;--i) 56 { 57 u=order[i];b[u]=1; 58 for (j=head[u];j;j=edge[j].next) 59 if(b[edge[j].to]&&b[u]) 60 { 61 merge(edge[j].to,u); 62 } 63 check(i); 64 } 65 //printf("%s\n","YES"); 66 for (i=1;i<=n;i++) 67 if (ans[i]==1) 68 { 69 putchar('Y'); 70 putchar('E'); 71 putchar('S'); 72 putchar('\n'); 73 } 74 else 75 { 76 putchar('N'); 77 putchar('O'); 78 putchar('\n'); 79 } 80 81 }