[bzoj3420]Poi2013 Triumphal arch_树形dp_二分
Triumphal arch
题目链接:https://lydsy.com/JudgeOnline/problem.php?id=3420
数据范围:略。
题解:
首先,发现$ k $具有单调性,我们可以二分。
现在考虑怎么验证?
看了题解...
我们设$ f_i $表示,如果当前人在$i$且要求合法的情况下,$i$的子树中最多要预先处理好多少个节点。
然后暴力树形$dp$转移即可。
代码:
#include <bits/stdc++.h> #define N 1000010 using namespace std; char *p1, *p2, buf[100000]; #define nc() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1 ++ ) int rd() { int x = 0, f = 1; char c = nc(); while (c < 48) { if (c == '-') f = -1; c = nc(); } while (c > 47) { x = (((x << 2) + x) << 1) + (c ^ 48), c = nc(); } return x * f; } int head[N], to[N << 1], nxt[N << 1], tot; inline void add(int x, int y) { to[ ++ tot] = y; nxt[tot] = head[x]; head[x] = tot; } int sz[N], ssz[N]; void dfs1(int p, int fa) { sz[p] = 1; for (int i = head[p]; i; i = nxt[i]) { if (to[i] != fa) { ssz[p] ++ ; dfs1(to[i], p); sz[p] += sz[to[i]]; } } } int k, f[N]; void dfs(int p, int fa) { f[p] = -k; for (int i = head[p]; i; i = nxt[i]) { if (to[i] != fa) { dfs(to[i], p); f[p] += f[to[i]] + 1; } } f[p] = max(f[p], 0); } bool check(int x) { k = x; dfs(1, 1); if (f[1]) { return false; } else { return true; } } int main() { int n = rd(); for (int i = 1; i < n; i ++ ) { int x = rd(), y = rd(); add(x, y), add(y, x); } dfs1(1, 1); if (n == 1) { puts("0"); return 0; } int l = 1, r = n, ans = n; while (l <= r) { int mid = (l + r) >> 1; // cout << mid << endl ; if (check(mid)) { r = mid - 1; ans = mid; } else { l = mid + 1; } } cout << ans << endl ; return 0; }
| 欢迎来原网站坐坐! >原文链接<