【传送门:BZOJ1060】
简要题意:
给出一棵树和根节点的编号,有一种道具可以使得一条边的权值+1,请问最少改变多少次使得根到所有叶子节点的权值和相等
题解:
首先我们可以确定达到根到所有叶子节点的权值和相等时,这个权值和一定是最大的根到叶子节点的链的权值和
所以我们用树形DP来维护f[i],f[i]表示从i点到叶子节点的最大权值和
然后ans=Σf[i]-f[y]-a[k].d(y表示i的儿子节点,a[k].d表示这条边的权值)
参考代码:
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; LL f[510000]; struct node { int x,y,next; LL d; }a[1100000];int len,last[510000]; void ins(int x,int y,int d) { len++; a[len].x=x;a[len].y=y;a[len].d=d; a[len].next=last[x];last[x]=len; } LL ans; void dfs(int x,int fa) { f[x]=0; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(y!=fa) { dfs(y,x); f[x]=max(f[x],f[y]+a[k].d); } } for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(y!=fa) ans+=f[x]-f[y]-a[k].d; } } int main() { int n; scanf("%d",&n); int root; scanf("%d",&root); len=0;memset(last,0,sizeof(last)); for(int i=1;i<n;i++) { int x,y,d; scanf("%d%d%d",&x,&y,&d); ins(x,y,d);ins(y,x,d); } ans=0; dfs(root,0); printf("%lld ",ans); return 0; }