积蓄程度_树形dp
题意:找一个点作为源点,问能往周围流的最多的水流。树形dp,dp数组代表以i为根的能流的所有水流,转移很简单,看代码,然后我们要处理一下从父节点流下来的值。如图。
积蓄程度_dp_02
之前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);
	}	
}