bzoj 5329 [SDOI2018] 戰略遊戲
阿新 • • 發佈:2018-12-23
轉換成 review work getch out char eof zoj -s
bzoj 5329 [SDOI2018] 戰略遊戲
Link
Solution
很容易想到虛樹
然後發現是一個圖。。。
現學圓方樹,套上去,做完了(模板題?)
就是直接上廣義圓方樹先把這玩意轉換成一棵樹,然後對當前詢問建立虛樹,斷掉虛樹裏任何一個點都合法(包括不出現的點,指那些在某個點和其虛樹上父親之間的點),統計一下即可
Code
// Copyright lzt #include<stdio.h> #include<cstring> #include<cstdlib> #include<algorithm> #include<vector> #include<map> #include<set> #include<cmath> #include<iostream> #include<queue> #include<string> #include<ctime> using namespace std; typedef long long ll; typedef std::pair<int, int> pii; typedef long double ld; typedef unsigned long long ull; typedef std::pair<long long, long long> pll; #define fi first #define se second #define pb push_back #define mp make_pair #define rep(i, j, k) for (register int i = (int)(j); i <= (int)(k); i++) #define rrep(i, j, k) for (register int i = (int)(j); i >= (int)(k); i--) #define Debug(...) fprintf(stderr, __VA_ARGS__) inline ll read() { ll x = 0, f = 1; char ch = getchar(); while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); } while (ch <= '9' && ch >= '0') { x = 10 * x + ch - '0'; ch = getchar(); } return x * f; } const int maxn = 200200; int tc, n, m, Q, tot, tim; int dfn[maxn], low[maxn], S[maxn], s[maxn], q[maxn]; int fa[maxn], dep[maxn], dis[maxn], sz[maxn], son[maxn], top[maxn]; struct Graph { int head[maxn], to[maxn << 1], nxt[maxn << 1], tot; void init() { memset(head, 0, sizeof(head)); tot = 0; } void addedge(int x, int y) { to[++tot] = y; nxt[tot] = head[x]; head[x] = tot; to[++tot] = x; nxt[tot] = head[y]; head[y] = tot; } } G1, G2; void Tarjan(int u) { tim++; dfn[u] = low[u] = tim; S[++S[0]] = u; for (int i = G1.head[u]; i; i = G1.nxt[i]) { int v = G1.to[i]; if (!dfn[v]) { Tarjan(v); low[u] = min(low[u], low[v]); if (low[v] >= dfn[u]) { // 單獨一條邊連接兩個點也得算作點雙 G2.addedge(++tot, u); int x = 0; do { x = S[S[0]]; S[0]--; G2.addedge(tot, x); } while (x != v); } } else low[u] = min(low[u], dfn[v]); } } void dfs1(int u, int pa) { fa[u] = pa; dep[u] = dep[pa] + 1; dis[u] = dis[pa] + (u <= n); sz[u] = 1; for (int i = G2.head[u]; i; i = G2.nxt[i]) { int v = G2.to[i]; if (v == pa) continue; dfs1(v, u); sz[u] += sz[v]; if (sz[v] > sz[son[u]]) son[u] = v; } } void dfs2(int u, int tp) { top[u] = tp; dfn[u] = ++tim; if (son[u]) dfs2(son[u], tp); for (int i = G2.head[u]; i; i = G2.nxt[i]) { int v = G2.to[i]; if (v == fa[u] || v == son[u]) continue; dfs2(v, v); } low[u] = tim; } int lca(int x, int y) { while (top[x] != top[y]) { if (dep[top[x]] < dep[top[y]]) swap(x, y); x = fa[top[x]]; } return dep[x] < dep[y] ? x : y; } bool cmp(int x, int y) { return dfn[x] < dfn[y]; } void work() { tc = read(); while (tc--) { n = read(), m = read(); G1.init(); G2.init(); tim = 0; tot = n; rep(i, 1, m) { int x = read(), y = read(); G1.addedge(x, y); } memset(dfn, 0, sizeof(dfn)); memset(son, 0, sizeof(son)); rep(i, 1, n) if (!dfn[i]) Tarjan(i); tim = 0; dfs1(1, 0); dfs2(1, 1); Q = read(); while (Q--) { int k = read(), len = k, tp = 0, ans = 0; rep(i, 1, k) s[i] = read(); sort(s + 1, s + k + 1, cmp); rep(i, 1, k - 1) s[++len] = lca(s[i], s[i + 1]); sort(s + 1, s + len + 1, cmp); len = unique(s + 1, s + len + 1) - (s + 1); ans = s[1] <= n; rep(i, 1, len) { while (tp && low[q[tp]] < dfn[s[i]]) tp--; if (tp) ans += dis[s[i]] - dis[q[tp]]; q[++tp] = s[i]; } printf("%d\n", ans - k); } } } int main() { #ifdef LZT freopen("in", "r", stdin); // freopen("out", "w", stdout); #endif work(); #ifdef LZT Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC); #endif }
Review
第一次寫圓方樹
如果知道圓方樹的話這題感覺很好想
bzoj 5329 [SDOI2018] 戰略遊戲