对于此题:2022_CCPC桂林站G. Group Homework的一些总结

传送门
题目转化为要么是两条不相交的链,要么是同一个顶点的四条链
感觉很妙的树形DP,用记忆化分别求出了以某一个顶点为父节点,某一顶点为子节点的以它为起点的最长链和不一定以它为起点的最长链

#include<bits/stdc++.h>
    
using namespace std;
    
const long long N = 2e6 + 10;
long long n,val[N];
vector<long long> g[N];
map<long long,long long> dp1[N];
map<long long,long long> dp2[N];

long long dfs1(long long u,long long fa) {
    if(dp1[u][fa]) return dp1[u][fa];
    long long maxn = val[u];
    for(auto i : g[u]) {
        if(i == fa) continue;
        maxn = max(maxn,dfs1(i,u) + val[u]);
    }
    return dp1[u][fa] = maxn;
}

long long dfs2(long long u,long long fa) {
    if(dp2[u][fa]) return dp2[u][fa];
    long long l[2] = {0},maxn = 0;
    for(auto i : g[u]) {
        if(i == fa) continue;
        maxn = max(maxn,dfs2(i,u));
        long long tmp = dfs1(i,u);
        if(tmp > l[0]) {
            l[1] = l[0];
            l[0] = tmp;
        }
        else if(tmp > l[1]) l[1] = tmp;
    }
    maxn = max(maxn,l[0] + l[1] + val[u]);
    return dp2[u][fa] = maxn;
}
    
void solve() {
    cin >> n;
    for(long long i = 1;i <= n;i++) cin >> val[i];
    for(long long u,v,i = 1;i < n;i++) {
        cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    long long ans = 0;
    for(long long i = 1;i <= n;i++) {
        vector<long long> l = {0,0,0,0};
        for(auto v : g[i]) l.push_back(dfs1(v,i));
        sort(l.begin(),l.end());
        reverse(l.begin(),l.end());
        ans = max(ans,l[0] + l[1] + l[2] + l[3]);
    }
    for(long long i = 1;i <= n;i++)
        for(auto v : g[i])
            ans = max(ans,dfs2(v,i) + dfs2(i,v));
    cout << ans << '\n';
}
    
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    long long t = 1;
    while(t--) solve();
    
    return 0;
}
posted @ 2025-07-08 09:55  孤枕  阅读(34)  评论(0)    收藏  举报