A 点对最大值

题目地址:

https://ac.nowcoder.com/acm/contest/5758/A

基本思路:

考虑树形dp,我们发现如果维护带两个端点的链比较麻烦,所以我们我们考虑维护只有一个端点的链,那么带两个端点的最长链也就是子树中带一个端点的最长两条链相连,因此设表示以为根的子树里的最长单端点链,那么我们能得到转移方程:,同时每次更新时我们还要再记录一下次长链,最长链加次长链就子树中权值最大的双端点最长链的权值了,每次更新答案就行了。

参考代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>
using namespace std;
#define IO std::ios::sync_with_stdio(false)
#define int long long
#define rep(i, l, r) for (int i = l; i <= r; i++)
#define per(i, l, r) for (int i = l; i >= r; i--)
#define mset(s, _) memset(s, _, sizeof(s))
#define pb push_back
#define pii pair <int, int>
#define mp(a, b) make_pair(a, b)
#define INF (int)1e18

inline int read() {
  int x = 0, neg = 1; char op = getchar();
  while (!isdigit(op)) { if (op == '-') neg = -1; op = getchar(); }
  while (isdigit(op)) { x = 10 * x + op - '0'; op = getchar(); }
  return neg * x;
}
inline void print(int x) {
  if (x < 0) { putchar('-'); x = -x; }
  if (x >= 10) print(x / 10);
  putchar(x % 10 + '0');
}

const int maxn = 1e6 + 10;
struct Edge{
    int to,w,next;
}edge[maxn << 1];
int n,c[maxn];
int cnt = 0,head[maxn];
void add_edge(int u,int v,int w){
  edge[++cnt].next = head[u];
  edge[cnt].to = v;
  edge[cnt].w = w;
  head[u] = cnt;
}
int ans = -INF;
int f[maxn];
void dfs(int u,int par){
  int mmx = c[u],mx = -INF;//mmx最长链,mx次长链;
  for(int i = head[u] ;i != -1 ; i = edge[i].next){
    int to = edge[i].to;
    if(to == par) continue;
    dfs(to,u);
    mx = max(mx,f[to] + edge[i].w);
    if(mmx < mx) swap(mmx,mx);
  }
  if(mx != -INF) ans = max(ans,mx + mmx);
  f[u] = mmx;
}
signed main() {
  IO;
  int t;
  cin >> t;
  while (t--) {
    cin >> n;
    //多组输入注意初始化;
    cnt = 0; mset(head,-1);
    ans = -INF;
    rep(i,2,n){
      int u,w;
      cin >> u >> w;
      add_edge(i,u,w);
      add_edge(u,i,w);
    }
    rep(i,1,n) cin >> c[i];
    dfs(1,0);
    cout << ans << '\n';
  }
  return 0;
}