Gold2
【题目描述】
FJ和他的奶牛们正在计划离开小镇做一次长的旅行,同时FJ想临时地关掉他的农场以节省一些金钱。
这个农场一共有被用M条双向道路连接的N个谷仓(1<=N,M<=200000)。为了关闭整个农场,FJ 计划每一次关闭掉一个谷仓。当一个谷仓被关闭了,所有的连接到这个谷仓的道路都会被关闭,而且再也不能够被使用。
FJ现在正感兴趣于知道在每一个时间(这里的“时间”指在每一次关闭谷仓之后的时间)时他的农场是否是“全连通的”——也就是说从任意的一个开着的谷仓开始,能够到达另外的一个谷仓。注意自从某一个时间之后,可能整个农场都开始不会是“全连通的”。
【输入格式】
输入的第一行是N和M。下面的M行每行都描述了一条连接两个谷仓的双向路径的两个端点(输入的点保证在1...N的范围内),最后的N行是一个1...N的排列,描述每一个谷仓被关闭的顺序。
【输出顺序】
输出一共有N行,每行可以是“YES”或者“NO”。第一行表示一开始时整个农场是否是“全连通的”,然后第i+1行表示在第i次的关闭谷仓之后整个农场是否是“全连通的”。
【样例输入】
4 3
1 2
2 3
3 4
3
4
1
2
【样例输出】
YES
NO
YES
YES
================================================================
#include<fstream>
#include<iostream>
#include<vector>
using namespace std;
const int maxn = 200005;
//ifstream fin("closing.in");
//ofstream fout("closing.out");
int n, m, fa[maxn], a[maxn];
vector<int>adj[maxn];
bool f[maxn], ans[maxn];
int find(int);
int main() {
freopen("closing.in", "r", stdin);
freopen("closing.out", "w", stdout);
//ios::sync_with_stdio(false);
//fin>>n>>m;
scanf("%d%d", &n, &m);
for(int i = 1; i != n + 1; ++i)fa[i] = i;
for(int i = 0; i != m; ++i) {
int u, v;
//fin>>u>>v;
scanf("%d%d", &u, &v);
adj[u].push_back(v);
adj[v].push_back(u);
}
for(int i = 0; i != n; ++i)scanf("%d", &a[i]); //fin>>a[i];
int cnt = 0;
for(int i = n - 1; i != -1; --i) {
++cnt;
for(int j = 0; j != adj[a[i]].size(); ++j) {
int node = adj[a[i]][j];
if(f[node] && find(node) != find(a[i])) {
--cnt;
fa[find(a[i])] = find(node);
}
}
ans[i] = cnt == 1;
f[a[i]] = true;
}
for(int i = 0; i != n; ++i)printf(ans[i] ? "YES\n" : "NO\n"); //fout<<(ans[i]?"YES":"NO")<<endl;
return 0;
}
int find(int root) {
return root == fa[root] ? root : fa[root] = find(fa[root]);
}