HDU 5923 Prediction(2016 CCPC東北地區大學生程序設計競賽 Problem B)
阿新 • • 發佈:2018-02-20
== hdu acm .cn pos ear memset long push
題目鏈接 2016 CCPC東北地區大學生程序設計競賽 B題
題意 給定一個無向圖和一棵樹,樹上的每個結點對應無向圖中的一條邊,現在給出$q$個詢問,
每次選定樹中的一個點集,然後真正被選上的是這些點以及這些點的所有祖先。
只有標號在樹中真正被選上的點代表的這些原圖中的邊是存在的,這樣就構成了一個新的圖。求這個圖的連通塊個數。
dfs整棵樹,記$f[x]$為若$x$以及$x$的所有祖先被選上,那麽構成的新的圖的並查集)
這個實現比較簡單,搜索的時候打上標記,回來的時候撤銷即可。
這樣預處理的時間復雜度是$O(nm)$的。
然後對於每個詢問,把$k$個詢問的並查集全部合並就可以了。
時間復雜度$O(nm + ∑kn)$
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) #define MP make_pair #define fi first #define se second typedef long long LL; const int N = 523; const int M = 1e4 + 10; int T; int ca = 0; int n, m, q; int ans; int a[M], b[M], c[N], f[M][N]; int father[N]; vector <int> g[M]; int getfather(int x){ return father[x] == x ? x : father[x] = getfather(father[x]); } void dfs(int x, int fa){ rep(i, 1, n) father[i] = f[fa][i]; int fx = getfather(a[x]); int fy = getfather(b[x]); father[fx] = fy; rep(i, 1, n) father[i] = getfather(i); rep(i, 1, n) f[x][i] = father[i]; for (auto u : g[x]){ dfs(u, x); } } int main(){ scanf("%d", &T); while (T--){ printf("Case #%d:\n", ++ca); scanf("%d%d", &n, &m); rep(i, 0, m + 1) g[i].clear(); rep(i, 2, m){ int x; scanf("%d", &x); g[x].push_back(i); } memset(a, 0, sizeof a); memset(b, 0, sizeof b); rep(i, 1, m){ scanf("%d%d", a + i, b + i); } rep(i, 1, n) f[0][i] = i; dfs(1, 0); scanf("%d", &q); while (q--){ int y; scanf("%d", &y); rep(i, 1, n) father[i] = i; rep(i, 1, y){ int x; scanf("%d", &x); memset(c, 0, sizeof c); rep(j, 1, n){ int now = f[x][j]; if (c[now]){ int fx = getfather(c[now]); int fy = getfather(j); father[fx] = fy; } c[now] = j; } } ans = 0; memset(c, 0, sizeof c); rep(i, 1, n){ int x = getfather(i); if (!c[x]) ++ans; c[x] = 1; } printf("%d\n", ans); } } return 0; }
HDU 5923 Prediction(2016 CCPC東北地區大學生程序設計競賽 Problem B)