[CF768G] The Winds of Winter
阿新 • • 發佈:2019-01-27
一個 暴力 erase else c++ pan 復雜 mes rep
顯然對於刪去一個點之後形成的森林, 就是把最大的那棵樹砍下來, 接到最小的樹上.
設刪去當前點刪去後形成的所有樹中最大的那一棵大小為\(Max\) , 最小的為Min, 次小值為Sec
設從最大樹砍掉的節點為u, 答案就是\(max\{Max - Size_u, Min + size_u, Sec\}\)
它關於\(Size_u\)變化的函數顯然是單峰的, 所以可以二分答案\(Ans\)一定要滿足\(Max - Size_u \leq Ans, Min + Size_u \leq Ans\)
就是: \(Max - Ans \leq Siz_u \leq Ans - Min\) , 只要找是否存在這樣的點即可
這樣處理的時候就很像DSU on tree, 每次暴力把輕兒子的貢獻加入整體, 重兒子直接繼承, 然後清空輕兒子的貢獻.
討論的時候要註意分三類討論, 分成兩大類, 分別是去掉這個點有無影響, 然後無影響又分為子樹和其他部分.
時間復雜度是\(O(n log^2 n log V)\)? 不知道為什麽跑這麽快
二分答案其實就是一個放寬答案取值區間的操作, 因為二分答案的時候保證了單調性, 所以可以直接計算考慮函數在定義域內的極值, 那麽就轉換成了最大/最小問題, 這也是他所以直接跟貪心相關.
那麽就自然要求統計樹上信息, 因為沒有修改, 所以直接DSU on tree,
Code
#include<bits/stdc++.h> using namespace std; #define rep(i, a, b) for(int i = (a), i##_end_ = (b); i <= i##_end_; ++i) #define drep(i, a, b) for(int i = (a), i##_end_ = (b); i >= i##_end_; --i) #define clar(a, b) memset((a), (b), sizeof(a)) #define debug(...) fprintf(stderr, __VA_ARGS__) typedef long long LL; typedef long double LD; int read() { char ch = getchar(); int x = 0, flag = 1; for (;!isdigit(ch); ch = getchar()) if (ch == ‘-‘) flag *= -1; for (;isdigit(ch); ch = getchar()) x = x * 10 + ch - 48; return x * flag; } void write(int x) { if (x < 0) putchar(‘-‘), x = -x; if (x >= 10) write(x / 10); putchar(x % 10 + 48); } const int Maxn = 500009; struct edge { int to, nxt; }g[Maxn << 1]; int n, fa[Maxn], head[Maxn], e, rt = 0; int ans[Maxn]; void add(int u, int v) { g[++e] = (edge){v, head[u]}, head[u] = e; } int size[Maxn], son[Maxn]; int val[Maxn]; multiset <int> Ots, ancestor, Self[Maxn]; void dfsInit(int u) { size[u] = 1; for (int i = head[u]; ~i; i = g[i].nxt) { int v = g[i].to; if (v != fa[u]) { dfsInit(v); if (size[v] > size[son[u]]) son[u] = v; size[u] += size[v]; } } if (u != rt) Ots.insert(size[u]); } void init() { clar(head, -1); n = read(); rep (i, 1, n) { int u = read(), v = read(); fa[v] = u; add(v, u); add(u, v); if (!u) rt = v; } dfsInit(1); } bool check(int opt, int val, int u, int Min, int Max) { if (opt == 1) { multiset <int> :: iterator IT = Self[son[u]].lower_bound(Max - val); if (IT != Self[son[u]].end() && (*IT) <= val - Min) return true; } else { multiset <int> :: iterator IT = Ots.lower_bound(Max - val); if (IT != Ots.end() && (*IT) <= val - Min) return true; IT = ancestor.lower_bound(Max - val + size[u]); if (IT != ancestor.end() && (*IT) <= val - Min + size[u]) return true; } return 0; } void dfs(int u) { if (u != rt) Ots.erase(Ots.find(size[u])); if (fa[u] && fa[u] != rt) ancestor.insert(size[fa[u]]); int Fisr = max(n - size[u], size[son[u]]), Seco = min(n - size[u], size[son[u]]), Min = n - size[u]; if (!Min) Min = size[son[u]]; for (int i = head[u]; ~i; i = g[i].nxt) { int v = g[i].to; if (v != fa[u] && v != son[u]) { dfs(v); for (multiset <int> :: iterator IT = Self[v].begin(); IT != Self[v].end(); ++IT) Ots.insert(*IT); Min = min(Min, size[v]); Seco = max(Seco, size[v]); } } if (son[u]) dfs(son[u]), Min = min(Min, size[son[u]]); for (int i = head[u]; ~i; i = g[i].nxt) { int v = g[i].to; if (v != fa[u] && v != son[u]) for (multiset <int> :: iterator IT = Self[v].begin(); IT != Self[v].end(); ++IT) Ots.erase(Ots.find(*IT)); } if (Seco != Fisr) { int l = Seco, r = Fisr, opt = (Fisr == size[son[u]]); while (l <= r) { int mid = (l + r) >> 1; if (check(opt, mid, u, Min, Fisr)) ans[u] = mid, r = mid - 1; else l = mid + 1; } } if (!ans[u]) ans[u] = Fisr; if (son[u]) swap(Self[son[u]], Self[u]); for (int i = head[u]; ~i; i = g[i].nxt) { int v = g[i].to; if (v != fa[u] && v != son[u]) for (multiset <int> :: iterator IT = Self[v].begin(); IT != Self[v].end(); Self[v].erase(IT++)) Self[u].insert(*IT); } if (fa[u] && fa[u] != rt) ancestor.erase(ancestor.find(size[fa[u]])); Self[u].insert(size[u]); } void solve() { dfs(rt); rep (i, 1, n) printf("%d\n", ans[i]); } int main() { freopen("del.in", "r", stdin); freopen("del.out", "w", stdout); init(); solve(); #ifdef Qrsikno debug("\nRunning time: %.3lf(s)\n", clock() * 1.0 / CLOCKS_PER_SEC); #endif return 0; }
?
[CF768G] The Winds of Winter