P3574 [POI2014]FAR-FarmCraft (樹形DP)
阿新 • • 發佈:2021-08-07
這題直接貪心顯然不可行.
考慮樹形dp,用 \(f_i\) 表示到 \(i\) 人後,以 \(i\) 為根的所有人安裝完的最短時間.
對於一個節點 \(u\), 假設拜訪子節點的順序為 \(v_1,v_2,...,v_m\) ,那麼得到轉移方程.
\[f_u = max(f_v + \sum\limits_{j = 1}^{i - 1}sum_j) \]其中 \(sum_i\) 表示拜訪完以 \(i\) 為根的子樹的所有人所花的時間,即 \((siz_i -1) *2\)
拜訪的順序考慮貪心
對於兩個相鄰整數 \(i,j\) ,必須滿足 \(f_j + \sum\limits_{k =1}^{j-1}sum_k<f_i+ \sum\limits_{k=1}^{i-1}sum_k+sum_j\)
\(\to f_j+sum_i < f_i+sum_j\\\to f_j-sum_j<f_i-sum_i\)
所以只要將 \(f_i - sum_i\) 從大到小排序即可.
const int N = 5e5 + 10; vector<int>e[N]; int f[N], a[N], g[N]; bool cmp(int x, int y) {return g[x] - f[x] > g[y] - f[y];} void dfs(int u, int fa) { for (int v : e[u]) { if (v == fa)continue; dfs(v, u); } sort(e[u].begin(), e[u].end(), cmp); if (u != 1) g[u] = a[u]; for (int v : e[u]) { if (v == fa)continue; g[u] = max(g[u], g[v] + f[u] + 1); f[u] += f[v] + 2; } } int main() { cin.tie(nullptr)->sync_with_stdio(false); int n; cin >> n; for (int i = 1; i <= n; ++i) cin >> a[i]; for (int i = 1, x, y; i < n; ++i) { cin >> x >> y; e[x].push_back(y); e[y].push_back(x); } dfs(1, 0); cout << max(g[1], f[1] + a[1]); }
The desire of his soul is the prophecy of his fate
你靈魂的慾望,是你命運的先知。