「BZOJ1827」奶牛大集会
题意:找一个点x使得$\sum c_i\cdot dis(i,x)$最小(其中dis表示i->x的距离)
做法:先跑出一个点的答案,然后在树上跳动,x->son的时候son这棵子树的答案都减去$\sum c_i*dis(x,son),i\in son$,其他节点都增加$\sum c_i*dis(x,son)$
#include<bits/stdc++.h> using namespace std; #define ll long long inline ll read() { ll x=0,f=1; char ch=getchar(); for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-')f=-f; for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; return x*f; } inline void chkmin( int &a,int b ) { if(a>b) a=b; } inline void chkmax( int &a,int b ) { if(a<b) a=b; } #define _ read() #define ln endl const int N=1e5+5; int cnt,head[N]; struct Edge { int to,nxt,w; } e[N<<1]; inline void insert( int u,int v,int w ) { e[++cnt]=(Edge) { v,head[u],w } ; head[u]=cnt; } inline void ins( int u,int v,int w ) { insert(u,v,w); insert(v,u,w); } ll sum[N],ans,tot,res; int a[N],n; inline void dfs_1( int x,int fa ) { sum[x]=a[x]; for( int i=head[x];i;i=e[i].nxt ) { if(e[i].to!=fa) { dfs_1(e[i].to,x); sum[x]+=sum[e[i].to]; ans+=e[i].w*sum[e[i].to]; } } } inline void dfs_2( int x,int fa ) { res=min(res,ans); for( int i=head[x];i;i=e[i].nxt ) { if(e[i].to!=fa) { ans+=(tot-sum[e[i].to])*e[i].w; ans-=e[i].w*sum[e[i].to]; dfs_2(e[i].to,x); ans-=(tot-sum[e[i].to])*e[i].w; ans+=e[i].w*sum[e[i].to]; } } } int main() { n=_; for( int i=1;i<=n;i++ ) a[i]=_,tot+=a[i]; for( int i=1;i<n;i++ ) { int u=_,v=_,w=_; ins(u,v,w); } dfs_1(1,0); res=ans; // cout<<sum[3]<<ln; // cout<<ans<<ln; dfs_2(1,0); cout<<res<<ln; }