Luogu3177 [HAOI2015]樹上染色
阿新 • • 發佈:2019-02-16
min sin amp des rst ble sum ref 距離
題目藍鏈
Description
給定一棵有\(n\)個節點的樹,初始全為白色。你要在裏面找到\(k\)個點,並把它們染成黑色。要使得染完色後,黑點兩兩之間的距離加上白點兩兩之間的距離的和最大
Solution
我們可以設\(dp[i][j]\)表示以\(i\)為根的子樹中選擇\(j\)個節點對全局答案的最大貢獻
然後對於每一個非葉子節點,枚舉兒子子樹進行轉移
\[
dp[u][j + k] \leftarrow dp[u][j] + dp[v][k] + val
\]
其中\(val\)為以\(v\)為根的子樹內的點通過對全局答案的貢獻
至於時間復雜度,我們可以發現任意一對點只會在它們LCA處被計算一次,所以復雜度為\(\mathcal{O}(n^2)\)
Code
#include <bits/stdc++.h> using namespace std; #define fst first #define snd second #define mp make_pair #define squ(x) ((LL)(x) * (x)) #define debug(...) fprintf(stderr, __VA_ARGS__) typedef long long LL; typedef pair<int, int> pii; template<typename T> inline bool chkmax(T &a, const T &b) { return a < b ? a = b, 1 : 0; } template<typename T> inline bool chkmin(T &a, const T &b) { return a > b ? a = b, 1 : 0; } inline int read() { int sum = 0, fg = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == ‘-‘) fg = -1; for (; isdigit(c); c = getchar()) sum = (sum << 3) + (sum << 1) + (c ^ 0x30); return fg * sum; } const int maxn = 2e3 + 10; int Begin[maxn], Next[maxn << 1], To[maxn << 1], w[maxn << 1], e; inline void link(int x, int y, int z) { To[++e] = y, Next[e] = Begin[x], Begin[x] = e, w[e] = z; } int n, m, sz[maxn]; LL dp[maxn][maxn]; inline void dfs(int now, int f) { int lim = 1; for (int i = Begin[now]; i; i = Next[i]) { int son = To[i]; if (son == f) continue; dfs(son, now); for (int j = min(lim, m); ~j; j--) for (int k = min(sz[son], m); ~k; k--) if (j + k <= m) chkmax(dp[now][j + k], dp[now][j] + dp[son][k] + (LL) w[i] * (k * (m - k) + (sz[son] - k) * (n - m - sz[son] + k))); lim += sz[son]; } sz[now] = lim; } int main() { #ifdef xunzhen freopen("tree.in", "r", stdin); freopen("tree.out", "w", stdout); #endif n = read(), m = read(); chkmin(m, n - m); for (int i = 1; i < n; i++) { int x = read(), y = read(), z = read(); link(x, y, z), link(y, x, z); } dfs(1, 0); printf("%lld\n", dp[1][m]); return 0; }
Luogu3177 [HAOI2015]樹上染色