HDU 6662 Acesrc and Travel 换根dp

本文探讨了在一个无根树结构中,通过两人轮流选择路径节点来最大化与对手得分差值的问题。利用状态转移方程和换根技巧,通过两次深度优先搜索实现了最优解的计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意就是给一个无根树,然后每次从一个点出发,两个人轮流决定下一点;对于一个点,Zhang获得a[i],Liu获得b[i]。每个人都想自己获得的与另一个人的差最大,求Zhang先手的最大差值。
Source:2019 Multi-University Training Contest 8

一个最大差值,一定是当前的点减去之前的最小值得到的,有状态转移:f(u,v,0)=min⁡{f(p,u,1)}f(u,v,1)=min⁡{f(p,u,0)}f(u,v,0)=\min\{f(p,u,1)\} \\f(u,v,1)=\min\{f(p,u,0)\} f(u,v,0)=min{f(p,u,1)}f(u,v,1)=min{f(p,u,0)}
因为起点是不确定的,考虑换根。再做一个dfs,向下扩展时,为了防止扩展到已扩展的节点,每次对于当前扩展的节点,记录一个前缀最小值。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<cstdlib>

#define inf 0x7fffffffffffffff
#define ll long long
#define mem(a, x) memset(a,x,sizeof(a))
#define iosup ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;

typedef pair<ll, ll> Pll;
const int N = 1e5 + 10;
ll dp[N][2], a[N], b[N];
vector<int> G[N];
vector<Pll> pre[N];
int n;

void dfs1(int u, int fa) {
    dp[u][0] = inf;
    dp[u][1] = inf;
    for (auto i:G[u])
        if (i != fa) {
            dfs1(i, u);
            dp[u][0] = min(dp[u][0], b[u] - a[u] - dp[i][1]);
            dp[u][1] = min(dp[u][1], a[u] - b[u] - dp[i][0]);
        }
    if (dp[u][0] == inf)
        dp[u][0] = b[u] - a[u], dp[u][1] = a[u] - b[u];
}

void dfs2(int u, int fa) {
    dp[u][0] = inf;
    dp[u][1] = inf;
    for (auto i:G[u]) {
        dp[u][0] = min(dp[u][0], b[u] - a[u] - dp[i][1]);
        dp[u][1] = min(dp[u][1], a[u] - b[u] - dp[i][0]);
        pre[u].push_back(Pll(dp[u][0], dp[u][1]));
    }
    ll t0 = inf, t1 = inf;
    for (int i = G[u].size() - 1; i >= 0; i--) {
        int v = G[u][i];
        dp[u][0] = t0;
        dp[u][1] = t1;
        if (i) {
            dp[u][0] = min(dp[u][0], pre[u][i - 1].first);
            dp[u][1] = min(dp[u][1], pre[u][i - 1].second);
        }
        if (dp[u][0] == inf)
            dp[u][0] = b[u] - a[u], dp[u][1] = a[u] - b[u];
        t0 = min(t0, b[u] - a[u] - dp[v][1]);
        t1 = min(t1, a[u] - b[u] - dp[v][0]);
        if (v != fa)
            dfs2(v, u);
    }
    dp[u][0] = t0;
    dp[u][1] = t1;
}

inline void init() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) G[i].clear();
    for (int i = 1; i <= n; i++) pre[i].clear();
    for (int i = 1; i <= n; i++)
        scanf("%lld", &a[i]);
    for (int i = 1; i <= n; i++)
        scanf("%lld", &b[i]);
    int u, v;
    for (int i = 1; i < n; i++) {
        scanf("%d%d", &u, &v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
}

int main() {
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int T;
    cin >> T;
    while (T--) {
        init();
        dfs1(1, 1);
        dfs2(1, 1);
        ll ans = -inf;
        for (int i = 1; i <= n; i++)
            ans = max(ans, dp[i][1]);
        printf("%lld\n", ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值