考虑树形dp,由于根不确定,所以我们先以1为根跑一次算出来g[i]表示i的子树内的最大值
然后再一次dfs,计算F[i]表示以i为物资投放点的答案
就得到了以上公式
这个换根的过程很重要!!
根法思想:先随便找一个点作为根进行dp,再以原来点为根进行dp,
类似点分治求重心(代填坑),通过与父亲值做减法,求出树上除v子树外最优值
适用范围:给出一棵树,要以每个点为根做一次dp的题目
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
typedef int ll;
const int maxn=2e5+5;
int n,head[maxn],cnt,in[maxn];
struct edge
{
int to,nxt;
ll v;
}e[maxn<<1];
void add(int x,int y,int z)
{
e[++cnt].to=y;
e[cnt].nxt=head[x];
e[cnt].v=(long long)z;
head[x]=cnt;
}
ll g[maxn],f[maxn];
void dfs1(int u,int fa)
{
for(int i=head[u];i;i=e[i].nxt)
{
int to=e[i].to;
if(to==fa) continue;
dfs1(to,u);
if(in[to]==1) g[u]+=e[i].v;
else g[u]+=min(e[i].v,g[to]);
}
}
void dfs2(int u,int fa)
{
for(int i=head[u];i;i=e[i].nxt)
{
int to=e[i].to;
if(to==fa) continue;
if(in[u]==1) f[to]=g[to]+e[i].v;
else f[to]=g[to]+min(f[u]-min(g[to],e[i].v),e[i].v);
dfs2(to,u);
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
memset(in,0,sizeof(in));
memset(head,0,sizeof(head));
cnt=0;
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
//for(int i=1;i<=2*n;i++) e[i].nxt=e[i].to=e[i].v=0;
scanf("%d",&n);
int x,y,z;
for(int i=1;i<n;i++)
{
scanf("%d%d%d",&x,&y,&z);
add(x,y,z); add(y,x,z);
in[x]++; in[y]++;
}
dfs1(1,0);
f[1]=g[1];
dfs2(1,0);
ll ans=0;
for(int i=1;i<=n;i++) ans=max(ans,f[i]);
printf("%d\n",ans);
}
return 0;
}