因为这个换根比较简单,只简述一下要维护的东西:
1,每个节点维护一个weight[]
,表示从叶子到根的方向,这个点最多能接纳的流量。
2,边权。
所以画画图,手动模拟一下就得出了以下转移:
void dfs2(int u,int fa)
{
for (int i = head[u]; i ; i = a[i].next) {
int v = a[i].to;
if (v == fa) continue;
int now = res[u] - a[i].w;
int c = 0;
c += min(a[i].w,now);
for (int j = head[v]; j ; j = a[j].next) {
int vv = a[j].to;
if (vv == u) continue;
c += min(a[j].w,weight[vv]);
}
// cout << v << ' ' << c << endl;
res[v] = c;
dfs2(v,u);
}
}
简单来说每个点的答案就是把当前节点v
周围的流量重新再加起来。这个可以由weight[],边权,res[u]
得出。
注意这里是顺推,因为下一个答案应有上一个答案得出。
//
// Created by SANZONG on 2021/7/8.
//
#include "bits/stdc++.h"
using namespace std;
const int maxn = 2e5;
struct node{
int next,to,w;
}a[maxn<<1];
int cnt;
int head[maxn << 1];
void add(int u,int v,int w)
{
a[++cnt].to = v;
a[cnt].w = w;
a[cnt].next = head[u];
head[u] = cnt;
}
int weight[maxn];
void dfs(int u,int fa)
{
if (a[head[u]].to == fa && !a[head[u]].next)
{
weight[u] = 0x3f3f3f3f;
return;
}
int w = 0;
for (int i = head[u]; i ; i = a[i].next) {
int v = a[i].to;
if (v == fa) continue;
dfs(v,u);
w += min(weight[v],a[i].w);
}
weight[u] = w;
}
int res[maxn];
void init()
{
cnt = 0;
memset(head,0,sizeof(head));
memset(a,0,sizeof(a));
memset(res,0,sizeof(res));
}
void dfs2(int u,int fa)
{
for (int i = head[u]; i ; i = a[i].next) {
int v = a[i].to;
if (v == fa) continue;
int now = res[u] - a[i].w;
int c = 0;
c += min(a[i].w,now);
for (int j = head[v]; j ; j = a[j].next) {
int vv = a[j].to;
if (vv == u) continue;
c += min(a[j].w,weight[vv]);
}
// cout << v << ' ' << c << endl;
res[v] = c;
dfs2(v,u);
}
}
signed main()
{
// freopen("in.txt","r",stdin);
int T;
cin >> T;
while (T--)
{
init();
int n;
cin >> n;
for (int i = 1; i <= n - 1; ++i) {
int u,v,w;
cin >> u >> v >> w;
add(u,v,w);
add(v,u,w);
}
int ans = 0;
dfs(1,0);
res[1] = weight[1];
dfs2(1,0);
for (int i = 1; i <= n; ++i) {
// cout << i << ' ' << res[i] << endl;
ans = max(ans,res[i]);
}
cout << ans << endl;
}
}