题意:找一个点作为源点,问能往周围流的最多的水流。树形dp,dp数组代表以i为根的能流的所有水流,转移很简单,看代码,然后我们要处理一下从父节点流下来的值。如图。
之前wa了三十分钟,是因为转移的时候忘记考虑了父节点子树给他的贡献,从上面留下来的水流包括父节点父节点流下来的水流+子树的水流,然后别忘记特判一下当两个端点的时候,两端都可以流。
#include<bits/stdc++.h>
using namespace std;
const int N=200010;
typedef long long ll;
ll dp[N];
ll up[N];
ll ans[N];
int h[N],e[N*2],ne[N*2],idx,w[N*2];
int d[N];
void add(int a,int b,int c)
{
w[idx]=c,e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int u,int fa)
{
for(int i=h[u];~i;i=ne[i])
{
int j=e[i];
if(j==fa)
continue;
//cout<<j<<endl;
dfs(j,u);
if(d[j]==1)
dp[u]+=w[i];
else
dp[u]+=min(1ll*w[i],dp[j]);
}
}
void dfs_2(int u,int fa)
{
for(int i=h[u];~i;i=ne[i])
{
int j=e[i];
if(j==fa) continue;
if(d[j]==1)
{
if(d[u]==1)
up[j]=w[i];
else
up[j]=min(w[i]*1ll,up[u]);
}
else
{
if(d[u]==1)
up[j]=w[i];
else
up[j]=min(w[i]*1ll,up[u]+dp[u]-min(dp[j],w[i]*1ll));
}
dfs_2(j,u);
}
}
int main()
{
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
for(int i=0;i<=n;i++)
h[i]=-1,d[i]=0,dp[i]=0,up[i]=0;
idx=0;
for(int i=0;i<n-1;i++)
{
int a,b,c;
cin>>a>>b>>c;
add(a,b,c);
add(b,a,c);
d[a]++;
d[b]++;
}
//cout<<d[1]<<' '<<d[2]<<endl;
dfs(1,-1);
ans[1]=dp[1];
dfs_2(1,-1);
ll maxv=ans[1];
//cout<<maxv<<endl;
for(int i=2;i<=n;i++)
ans[i]=dp[i]+up[i],maxv=max(maxv,ans[i]);
printf("%lld\n",maxv);
}
}