Acesrc and Travel【換根樹dp】

考慮固定根(起點)情況下的最優解,可以用dp容易求出。

考慮換根操作,假設當前根爲u,需要換成v。(v是以1爲根情況下u的子節點)

那麼需要保證v->u後,u不能再返回v,所以需要記錄最優值和次優值。

當發現u的最優值不經過v,用最優值對v進行轉移,否則用次優值進行轉移。

基本做法就是這樣,但是在實際寫代碼的過程中,發現了2種需要特判的情況。

第一種:在寫dfs2時發現u沒有次優解,這時v的轉移會出現問題。

第二種:以①爲根的情況下的葉子節點,在dfs2時必須轉移,即使轉移並不優秀。(對應題目的條件如果能走,那麼不會停)

 

警告:代碼可讀性極差,寫的很麻煩,不建議看。

換一下人名, Alice 來表示zhang,bob來表示liu。

在dfs1後:

dp[i][0][0]表示以①爲根的情況下,以 i 號爲起點,輪到Alice移動,僅走 i 的子樹,能獲得的最大差值。

dp[i][0][1]表示以①爲根的情況下,以 i 號爲起點,輪到Alice移動,僅走 i 的子樹,能獲得的次大差值。

dp[i][1][0]表示以①爲根的情況下,以 i 號爲起點,輪到Bob移動,僅走 i 的子樹,能獲得的最小差值。

dp[i][1][1]表示以①爲根的情況下,以 i 號爲起點,輪到Bob移動,僅走 i 的子樹,能獲得的次小差值。

在dfs2後:

dp[i][0][0]表示以 i 號爲起點,輪到Alice移動,能獲得的最大差值。

dp[i][0][1]表示以 i 號爲起點,輪到Alice移動,能獲得的次大差值。

dp[i][1][0]表示以 i 號爲起點,輪到Bob移動,能獲得的最小差值。

dp[i][1][1]表示以 i 號爲起點,輪到Bob移動,能獲得的次小差值。

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<long long,int>
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
#define pb push_back
const int N = 1e5+1000;
vector<int>nxt[N];
ll s[N];
ll dp[N][2][2],ans;
bool yezi[N];
int n;
void up(ll &x,ll y) {x = max(x,y);}
void down(ll &x,ll y) {x = min(x,y);}
void dfs1(int u,int f) {
    dp[u][0][0] = -4e18;
    dp[u][0][1] = -4e18;
    dp[u][1][0] = 4e18;
    dp[u][1][1] = 4e18;
    yezi[u] = 1;
    for(auto v:nxt[u]) {
        if(v==f) continue;
        yezi[u] = 0;
        dfs1(v, u);
        up(dp[u][0][1],dp[v][1][0]+s[u]);
        if(dp[u][0][1]>dp[u][0][0]) swap(dp[u][0][1],dp[u][0][0]);
        down(dp[u][1][1],dp[v][0][0]+s[u]);
        if(dp[u][1][1]<dp[u][1][0]) swap(dp[u][1][1],dp[u][1][0]);
    }
    if(yezi[u]) dp[u][0][0] = dp[u][0][1] = dp[u][1][1] = dp[u][1][0] = s[u]; 
}
void dfs2(int u,int f) {
    ans = max(ans,dp[u][1][0]);
    for(auto v:nxt[u]) {
        if(v==f) continue;
        if(!yezi[v]) {   
            if(dp[v][0][0]==dp[u][1][0]-s[u]) up(dp[v][0][1],dp[u][1][1]+s[v]);
            else up(dp[v][0][1],dp[u][1][0]+s[v]);
            if(dp[v][0][1]>dp[v][0][0]) swap(dp[v][0][1],dp[v][0][0]);

            if(dp[v][1][0]==dp[u][0][0]-s[u]) down(dp[v][1][1],dp[u][0][1]+s[v]);
            else down(dp[v][1][1],dp[u][0][0]+s[v]);
            if(dp[v][1][1]<dp[v][1][0]) swap(dp[v][1][1],dp[v][1][0]);
        }
        else {  //處理第二種特殊情況
            if(s[v]==dp[u][1][0]-s[u]) up(dp[v][0][1],dp[u][1][1]+s[v]);
            else up(dp[v][0][1],dp[u][1][0]+s[v]);
            if(dp[v][0][1]>dp[v][0][0]) swap(dp[v][0][1],dp[v][0][0]);

            if(s[v]==dp[u][0][0]-s[u]) down(dp[v][1][1],dp[u][0][1]+s[v]);
            else down(dp[v][1][1],dp[u][0][0]+s[v]);
            if(dp[v][1][1]<dp[v][1][0]) swap(dp[v][1][1],dp[v][1][0]);
        }
        dfs2(v,u);
    }
}
int main() {
   // freopen("a.txt","r",stdin);
    ios::sync_with_stdio(0);
    int T;
    cin>>T;
    while(T--) {
        cin>>n;
        rep(i, 1, n) {
            cin>>s[i];
            yezi[i] = 0;
            nxt[i].clear();
        }
        rep(i, 1, n) {
            int x;
            cin>>x;
            s[i] -= x;
        }
        rep(i, 1, n-1) {
            int u,v;
            cin>>u>>v;
            nxt[u].pb(v);
            nxt[v].pb(u);
        }
        ans = -4e18;
        dfs1(1,0);
        if(nxt[1].size()==1) {  //處理第一種特殊情況
            dp[1][0][1] = s[1];
            dp[1][1][1] = s[1];
        }
        rep(i, 1, n) {        //處理第二種特殊情況
            if(yezi[i]) {
                dp[i][0][0] = -4e18;
                dp[i][0][1] = -4e18;
                dp[i][1][0] = 4e18;
                dp[i][1][1] = 4e18;
            }
        }
        dfs2(1,0);
        cout<<ans<<endl;
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章