HDU 6662 Acesrc and Travel
題目大意
兩個人在一棵樹上博弈,走到點會獲得的收益,走到節點會獲得的收益。可以任意選擇一個起始點,然後在選擇的點的相鄰點且沒有被選過的點中選擇一個走下去,然後進行相同的操作,現在兩人都想最大化與對手的差異,求的最大值。
分析
爲了方便計算,我們記。
由於兩人均想最大化與對手之間的差異,我們不難發現選擇了一個點後,一定會選擇相鄰點中最小的;反過來,一定會選擇最大的走下去。
那麼考慮這樣設計狀態:設狀態爲當前兩人在節點,接下來該選點,走到以爲根的子樹中的某個葉子節點的最優的答案;同理,狀態爲該選點時的最優答案。
不難列出狀態轉移:
這樣我們就做出了固定一個起點的轉移方案。
但這題的起點是不固定的,那麼我們考慮換根。
我們再定義分別爲現在在節點,輪到選點且從往父親走的方案。
那麼就有兩種轉移方式:(其中是的兒子)
- 往父親的父親方向:;
- 往兄弟方向:。
- 最後在兩種轉移方式中取較大值/較小值即可。
注意到我們的轉移方向可能和的最優值轉移方向相同,所以我們必須記錄一下次優值,當發現轉移方向是的最優值方向時就用次優值轉移。
最後答案爲
注意當是葉子節點時,它對答案的貢獻僅爲
參考代碼
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int Maxn = 1e5;
const ll INF = 1e18;
int N, val[Maxn + 5];
vector<int> G[Maxn + 5];
void addedge(int u, int v) {
G[u].push_back(v);
G[v].push_back(u);
}
int cnt_son[Maxn + 5];
ll f1[2][Maxn + 5], f2[2][Maxn + 5], g1[Maxn + 5], g2[Maxn + 5];
void PreDFS(int u, int fa) {
for(int i = 0; i < (int)G[u].size(); i++) {
int v = G[u][i];
if(v == fa) continue;
PreDFS(v, u);
cnt_son[u]++;
if(f1[0][u] < f2[0][v] + val[u])
f1[1][u] = f1[0][u], f1[0][u] = f2[0][v] + val[u];
else if(f1[1][u] < f2[0][v] + val[u])
f1[1][u] = f2[0][v] + val[u];
if(f2[0][u] > f1[0][v] + val[u])
f2[1][u] = f2[0][u], f2[0][u] = f1[0][v] + val[u];
else if(f2[1][u] > f1[0][v] + val[u])
f2[1][u] = f1[0][v] + val[u];
}
if(cnt_son[u] == 0) {
f1[0][u] = f1[1][u] = val[u];
f2[0][u] = f2[1][u] = val[u];
}
}
void DFS(int u, int fa) {
for(int i = 0; i < (int)G[u].size(); i++) {
int v = G[u][i];
if(v == fa) continue;
if(cnt_son[u] == 1) {
g1[v] = g2[u] + val[v], g2[v] = g1[u] + val[v];
} else {
ll mx = f1[0][u];
if(f1[0][u] == f2[0][v] + val[u])
mx = f1[1][u];
if(u != 1) mx = max(mx, g2[u]);
g1[v] = mx + val[v];
ll mn = f2[0][u];
if(f2[0][u] == f2[0][v] + val[u])
mn = f2[1][u];
if(u != 1) mn = min(mn, g1[u]);
g2[v] = mn + val[v];
}
DFS(v, u);
}
}
int main() {
#ifdef LOACL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
int _;
scanf("%d", &_);
while(_--) {
scanf("%d", &N);
for(int i = 1; i <= N; i++) {
G[i].clear();
cnt_son[i] = 0;
f1[0][i] = f1[1][i] = -INF;
f2[0][i] = f2[1][i] = INF;
}
for(int i = 1; i <= N; i++)
scanf("%d", &val[i]);
for(int i = 1; i <= N; i++) {
int x;
scanf("%d", &x);
val[i] -= x;
}
for(int i = 1; i < N; i++) {
int u, v;
scanf("%d %d", &u, &v);
addedge(u, v);
}
PreDFS(1, 0);
g1[1] = g2[1] = val[1];
DFS(1, 0);
ll ans = f2[0][1];
for(int i = 2; i <= N; i++) {
if(G[i].size() == 1) ans = max(ans, g1[i]);
else ans = max(ans, min(g1[i], f2[0][i]));
}
printf("%lld\n", ans);
}
return 0;
}/**/