題目鏈接
Solution
辣雞題...因爲一個函數名看了我賊久。
思路很簡單,可以先隨便指定一個根,然後考慮換根的變化。
每一次把根從 \(x\) 換成 \(x\) 的一個子節點 \(y\),記錄一下每個節點的子樹牛數目 \(son\)。
令 \(sum\) 爲所有節點上牛的數目,那麼每一次換根變化爲 \((sum-son_y*2)*w\)。
然後就可以統計了,複雜度 \(O(n)\) 。
Code
#include<bits/stdc++.h>
#define N 100008
#define ll long long
using namespace std;
void in(ll &x)
{
char ch=getchar();ll f=1,w=0;
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){w=w*10+ch-'0';ch=getchar();}
x=f*w; return;
}
struct sj{
ll to,next,w;
}a[N*2];
ll head[N],size,c[N],n;
void add(ll x,ll y,ll z)
{
a[++size].to=y;
a[size].next=head[x];
head[x]=size;
a[size].w=z;
}
ll sum[N],son[N],ans[N],som[N],Ans,Sum;
void dfs(ll x,ll fr)
{
son[x]=c[x];
for(ll i=head[x];i;i=a[i].next)
{
ll tt=a[i].to;
if(tt==fr)continue;
dfs(tt,x);
son[x]+=son[tt];
sum[x]+=(a[i].w*son[tt]+sum[tt]);
}
}
void work(ll x,ll fr)
{
for(ll i=head[x];i;i=a[i].next)
{
ll tt=a[i].to;
if(tt==fr)continue;
som[tt]=Sum-son[tt];
ans[tt]=ans[x]+som[tt]*a[i].w-son[tt]*a[i].w;
Ans=min(Ans,ans[tt]);
work(tt,x);
}
}
int main()
{
in(n);
for(ll i=1;i<=n;i++) in(c[i]),Sum+=c[i];
for(ll i=1;i<n;i++)
{
ll x,y,w;
in(x),in(y),in(w);
add(x,y,w),add(y,x,w);
}
dfs(1,0); Ans=0x3f3f3f3f3f3f3f;
ans[1]=sum[1]; work(1,0);
cout<<min(ans[1],Ans)<<endl;
return 0;
}