[題解][CF-1292C]Xenon‘s Attack on the Gangs
阿新 • • 發佈:2021-12-16
設\(sz_{root}(u)\)表示以\(root\)為根,子樹\(T(u)\)的大小, \(fa_{root}(u)\)表示以\(root\)為根,節點\(u\)的父親。這兩個東西可以\(O(n^2)\)預處理。
轉化一下問題:
\[ans=\sum\limits_{x = 1}^{n - 1} \sum\limits_{u,v \in V} [\mathrm{mex}(u,v) \ge x] \]那麼現在考慮從小到大加入每一個邊權,首先加入邊權\(0\):
那麼一定可以得到\(sz_{u}(v) \times sz_{v}(u)\)的貢獻。那麼接下來加入權值\(1\)。
假如說\(0,1\)
接著想想,將\(0,1\)連在一起有利無害,那麼就連在一起吧。。。這啟示我們,接下來放邊權的時候,一定是儘量將之前已經放了邊權形成的路徑延長一個位置(這個想法比較古怪)。也就是說,對於\(\mathrm{mex}\)最長的一條路徑,它所包含的邊權可以組成\([0,路徑長度-1]\)這一個區間的,而且區間的兩個端點一定在葉子上。接下來設定一條最長的路徑\((u,v)\),我們想想怎麼在上面填邊權。首先在某個位置填上\(0\),然後任選左右其中位置填上\(1\),然後再選左右其中一個填上\(2\)。每次填上一個邊權之後,在答案中加入路徑兩邊連著的子樹的大小。這不就是\(dp\)
那麼可以得到:
\[f(u,v)=\begin{cases} \max\left\{f(fa_{v}(u),v), f(u, fa_{u}(v)\right\} + sz_{u}(v)\times sz_{v}(u) & u \ne v\\ 0 & u = v \end{cases} \]#include <bits/stdc++.h> #define LL long long using namespace std; const int maxn = 3e3 + 5; struct Edge { int v, nex; Edge(int v = 0, int nex = 0) : v(v), nex(nex) {} } E[maxn << 1]; int hd[maxn], tote; void addedge(int u, int v) { E[++tote] = Edge(v, hd[u]), hd[u] = tote; E[++tote] = Edge(u, hd[v]), hd[v] = tote; } LL sz[maxn][maxn], fat[maxn][maxn], f[maxn][maxn]; int n, rt; void init(int u, int fa) { fat[rt][u] = fa, sz[rt][u] = 1; for (int i = hd[u]; i; i = E[i].nex) { int v = E[i].v; if (v == fa) continue; init(v, u), sz[rt][u] += sz[rt][v]; } } LL dp(int u, int v) { if (u == v) return 0; if (~f[u][v]) return f[u][v]; return f[u][v] = max(dp(fat[v][u], v), dp(u, fat[u][v])) + sz[u][v] * sz[v][u]; } int main() { memset(f, -1, sizeof(f)); scanf("%d", &n); for (int i = 1; i < n; i++) { int u, v; scanf("%d%d", &u, &v); addedge(u, v); } for (int i = 1; i <= n; i++) rt = i, init(i, 0); LL ans = 0; for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) ans = max(ans, dp(i, j)); printf("%lld\n", ans); return 0; }