题解:[USACO10MAR] Great Cow Gathering G
树型 DP
换根树型 DP。
令 \(dis_x\) 表示节点 \(x\) 的子树内不方便程度的和。
显然,\(dis_x\) 会因为根节点的不同而不同,我们考虑如何转换。
令 \(dp_x\) 表示以 \(x\) 为根节点时,不方便程度之和。
原来的 \(dis_x\) 则是在以 \(1\) 为根节点的条件下求得的。
则:
\[dp_1=dis_1
\]
对于节点 \(x\) 的子节点 \(y\),有:
\[dp_y=dp_x-size_y\times w_{x,y}+(m-size_y)\times w_{x,y}
\]
其中,\(size_p\) 表示以 \(1\) 为根节点的情况下,\(p\) 的子树内牛的总数。
根节点从 \(x\) 换到 \(y\),显然是 \(y\) 及其子树抬升了一级,\(x\) 及其除 \(y\) 以外的子树下降了一级,由此可得上文递推式。
AC 代码
//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
typedef long long ll;
constexpr const int N=1e5;
struct graph{
struct node{
int v,r,w;
}a[2*(N-1)+1];
int h[N+1];
void create(int u,int v,int w){
static int top;
a[++top]={v,h[u],w};
h[u]=top;
}
}g;
int n,m,c[N+1];
ll size[N+1],dis[N+1];
void dfs1(int x,int fx){
size[x]=c[x];
for(int i=g.h[x];i>0;i=g.a[i].r){
if(g.a[i].v==fx)continue;
dfs1(g.a[i].v,x);
size[x]+=size[g.a[i].v];
dis[x]+=dis[g.a[i].v]+size[g.a[i].v]*g.a[i].w;
}
}
ll dp[N+1];
void dfs2(int x,int fx){
for(int i=g.h[x];i>0;i=g.a[i].r){
if(g.a[i].v==fx)continue;
dp[g.a[i].v]=dp[x]-size[g.a[i].v]*g.a[i].w+(m-size[g.a[i].v])*g.a[i].w;
dfs2(g.a[i].v,x);
}
}
int main(){
/*freopen("test.in","r",stdin);
freopen("test.out","w",stdout);*/
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",c+i);
m+=c[i];
}
for(int i=1;i<n;i++){
int u,v,w;
scanf("%d %d %d",&u,&v,&w);
g.create(u,v,w);
g.create(v,u,w);
}
dfs1(1,0);
dp[1]=dis[1];
dfs2(1,0);
ll ans=(1ll<<62);
for(int i=1;i<=n;i++){
ans=min(ans,dp[i]);
}
printf("%lld\n",ans);
/*fclose(stdin);
fclose(stdout);*/
return 0;
}

浙公网安备 33010602011771号