USACO 2016 US Open Contest Gold T2: Closing the Farm

题目大意

FJ和他的奶牛们正在计划离开小镇做一次长的旅行,同时FJ想临时地关掉他的农场以节省一些金钱。

这个农场一共有被用M条双向道路连接的N个谷仓(1<=N,M<=200000)。为了关闭整个农场,FJ 计划每一次关闭掉一个谷仓。当一个谷仓被关闭了,所有的连接到这个谷仓的道路都会被关闭,而且再也不能够被使用。

FJ现在正感兴趣于知道在每一个时间(这里的“时间”指在每一次关闭谷仓之前的时间)时他的农场是否是“全连通的”——也就是说从任意的一个开着的谷仓开始,能够到达另外的一个谷仓。注意自从某一个时间之后,可能整个农场都开始不会是“全连通的”。

题目分析

对于每一个点,我们要关闭它,然后断开所有与它相连的边,并且把它标记为已删除,接着按照题目判断就好了。

 

事实上,这种没有强制在线的断边似乎都可以并查集搞。

离线后,然后倒着加边,最后倒着回答询问就好了。

 

主要是对于这个题目,你需要O(1)判断一张图是否联通。

这在并查集如果你枚举每个点算联通块个数的话会超时

不如直接维护个并查集的size,然后判断下当前size是否为图中点数就好了。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int MAXN=3e5+10;
 4 
 5 vector<int> G[MAXN];
 6 set<int> s;
 7 int n,m;
 8 int q[MAXN],ans[MAXN];
 9 int f[MAXN],siz[MAXN];
10 inline int Find(int x){
11     return f[x]==x?x:f[x]=Find(f[x]);
12 }
13 inline void Merge(int x,int y){
14     int ex=Find(x),ey=Find(y);
15     if(ex!=ey){
16         if(siz[ey]<siz[ex]) swap(ex,ey);
17         f[ex]=ey;
18         siz[ey]+=siz[ex];
19     }
20 }
21 int main(){
22     scanf("%d%d",&n,&m);
23     for(int i=1;i<=n;++i){
24         f[i]=i;
25         siz[i]=1;
26     }
27     for(int i=1,u,v;i<=m;++i){
28         scanf("%d%d",&u,&v);
29         G[u].push_back(v);
30         G[v].push_back(u);
31     }
32     for(int i=1;i<=n;++i)
33         scanf("%d",&q[i]);
34     for(int i=n,u;i>=1;--i){
35         u=q[i];
36         s.insert(u);
37         for(int k=0;k<(int)G[u].size();++k)
38             if(s.count(G[u][k])) Merge(G[u][k],u);
39         int rt=Find(*s.begin());
40         ans[i]=siz[rt]==(int)s.size();
41     }
42     for(int i=1;i<=n;++i)
43         printf("%s\n",ans[i]?"YES":"NO");
44     return 0;
45 }

 

posted @ 2019-07-20 20:16  LI_dox  阅读(229)  评论(0编辑  收藏  举报