题意:给你一个n个节点的树,每条边有个流量上限。
选择一个节点为根节点,求它流向所有子节点的流量之和,根节点的流量是无限的
做法:设flow[i]为i节点的流量和,
状态方程:flow[i]=∑min(flow[j],edge[i][j])(j是i的儿子)
换根dp一下即可。注意叶子节点要特判
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define per(i,a,b) for(int i=a;i>=(b);--i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair<int, int>
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=2e5+10;
vector<pair<int,ll> >G[N];
vector<ll>pre[N];
ll n,flow[N],ans;
void dfs1(int u,int fa)
{
for(auto now:G[u]){
int v=now.first;
ll w=now.second;
if(v==fa) continue;
if(G[v].size()==1){
flow[u]+=w;
}
else{
dfs1(v,u);
flow[u]+=min(flow[v],w);
}
}
}
void dfs2(int u,int fa)
{
//printf("u:%d fa:%d fl:%lld\n",u,fa,flow[u]);
ans=max(ans,flow[u]);
pre[u].push_back(0);
for(int i=0;i<G[u].size();++i){
auto now=G[u][i];
int v=now.first;ll w=now.second;
pre[u].push_back(pre[u][i]);
if(G[v].size()==1)pre[u][i+1]+=w;
else pre[u][i+1]+=min(flow[v],w);
}
ll last=0;
//puts("****");
for(int i=G[u].size()-1;i>=0;--i){
auto now=G[u][i];
int v=now.first;
ll w=now.second;
flow[u]=0;
ll nw=pre[u][i]+last;
flow[u]=nw;
if(G[u].size()==1) flow[v]+=w;
else flow[v]+=min(w,flow[u]);
if(v!=fa) dfs2(v,u);
if(G[u].size()==1) last+=w;
else last+=min(w,flow[u]);
}
}
void solve()
{
scanf("%d",&n);
for(int i=0;i<=n+1;++i){
G[i].clear();
pre[i].clear();
flow[i]=0;
}
for(int i=1;i<n;++i){
int u,v;
ll w;
scanf("%d%d%lld",&u,&v,&w);
G[u].push_back(make_pair(v,w));
G[v].push_back(make_pair(u,w));
flow[i]=0;
}
ans=0;
dfs1(1,-1);
//for(int i=1;i<=n;++i) printf("i:%d flow:%lld\n",i,flow[i]);
dfs2(1,-1);
printf("%lld\n",ans);
}
int main()
{
//ios::sync_with_stdio(false);
//freopen("input.txt", "r", stdin);
//freopen("output.txt", "w", stdout);
int _;cin>>_;while(_--)
solve();
}