HYSBZOJ 3677 [Apio2014]連珠線
題目大意
BZOJ 上的題面太毒瘤了,我來重寫一下
給定個珠子,現在可以進行如下操作:
Append(w,v)
:將一個新的珠子用紅線與一個已經添加了的珠子連起來;Insert(w,u,v)
:將一個新的珠子插入到用紅線連起來的珠子,即斷開的紅線,並用藍線連接和。
給出最後的狀態(保證是一棵樹),即珠子的連接狀態和線的長度,現在要求最大化藍線的總長度。
分析
考慮最後的狀態下藍線的連接情況,一定是從某個節點的兒子 -> 某個節點 -> 它的父親。
明顯的換根 DP 。
設狀態爲當前在節點,其中表示不是藍線的中點,而表示是藍線的中點。
考慮的轉移,對於,我們要使它不是中點,我們就要滿足對於它的任何一個兒子,它作爲中點()和它也不是中點()。則我們得出的轉移:
考慮的轉移,對於,我們可以枚舉這條藍線連接的兒子,其他的點仍然按照的方法轉移,那麼對於,我們必須先減掉它原來的貢獻,再加上它現在的貢獻,所以得出的狀態轉移:
這樣我們做出了以某個節點爲根的狀態轉移。
考慮換根:一個點的兒子在成爲它的父親之後,原來的兒子的貢獻就會消失,這個點的貢獻就會加到原來的兒子(現在的父親)上去。顯然必須記錄次大值
爲了方便地換根,我們另外定義狀態表示在計算的值時不考慮第棵子樹的代價,另外,爲了方便,我們也可以順帶記錄下去掉這個子樹後的最大值。
考慮換根時的一些細節。注意到一個點換了根後,它的父親會變成它的兒子(即對產生貢獻),所以我們應該先重新計算它的父親對它的貢獻,再來統計答案和換根。
參考代碼
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
const int Maxn = 200000;
const int INF = 0x3f3f3f3f;
int N;
vector<pair<int, int> > G[Maxn + 5];
void addedge(int u, int v, int w) {
G[u].push_back(make_pair(v, w));
G[v].push_back(make_pair(u, w));
}
int f[2][Maxn + 5];
vector<int> val[2][Maxn + 5], mx_son_val[Maxn + 5];
vector<int> son[Maxn + 5];
int len[Maxn + 5];
void PreDFS(int u, int fa) {
f[0][u] = 0, f[1][u] = -INF;
int mx1 = -INF, mx2 = -INF;
for(int i = 0; i < (int)G[u].size(); i++) {
int v = G[u][i].first, w = G[u][i].second;
if(v == fa) continue;
PreDFS(v, u), len[v] = w;
son[u].push_back(v);
f[0][u] += max(f[0][v], f[1][v] + w);
int tmp = f[0][v] + w - max(f[0][v], f[1][v] + w);
if(tmp > mx1) mx2 = mx1, mx1 = tmp;
else if(tmp > mx2) mx2 = tmp;
}
f[1][u] = f[0][u] + mx1;
for(int i = 0; i < (int)G[u].size(); i++) {
int v = G[u][i].first, w = G[u][i].second;
if(v == fa) continue;
val[0][u].push_back(f[0][u] - max(f[0][v], f[1][v] + w));
int tmp = f[0][v] + w - max(f[0][v], f[1][v] + w);
if(tmp == mx1) {
val[1][u].push_back(val[0][u].back() + mx2);
mx_son_val[u].push_back(mx2);
} else {
val[1][u].push_back(val[0][u].back() + mx1);
mx_son_val[u].push_back(mx1);
}
}
}
int ans;
void DFS(int u, int fa) {
for(int i = 0; i < (int)son[u].size(); i++) {
int v = son[u][i];
f[0][u] = val[0][u][i], f[1][u] = val[1][u][i];
if(fa != 0) {
f[0][u] += max(f[0][fa], f[1][fa] + len[u]);
f[1][u] = f[0][u] + max(mx_son_val[u][i], f[0][fa] + len[u] - max(f[0][fa], f[1][fa] + len[u]));
}
ans = max(ans, f[0][v] + max(f[0][u], f[1][u] + len[v]));
DFS(v, u);
}
}
int main() {
#ifdef LOACL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
scanf("%d", &N);
for(int i = 1; i < N; i++) {
int u, v, w;
scanf("%d %d %d", &u, &v, &w);
addedge(u, v, w);
}
PreDFS(1, 0);
DFS(1, 0);
printf("%d\n", ans);
return 0;
}
//f[u][0/1]:
//f[u][0] = sum(max(f[v][0], f[v][1] + w(u, v)))
//f[u][1] = f[u][0] + max(f[v][0] + w(u, v) - max(f[v][0], f[v][1] + w(u, v)))