版权声明:原创,未经作者允许禁止转载 https://blog.csdn.net/Mr_wuyongcong/article/details/85208305
正题
题目大意
一棵树,每个叶子节点有权值,每个点的权值是它这棵子树中的所有叶子节点权值之和。可以减少叶子节点的值,要求减少最少的值使得对于每个点,它的所有子节点的权值都相等。
解题思路
如果将叶子节点的深度优先访问顺序排好,那么就是一个序列。对于这个序列,我们只可以区间减少。那么我们可以先将一个区间减到满足要求,再考虑更大的区间。
对于每个点我们先不考虑原本权值。我们对于每个点我们构建一种系数
。
对于第
个点,如果它的子树已经平衡了,那么当我们将总值减去
的倍数时它还是平衡的。
明显这个系数为
然后这个点的
#include<cstdio>
#include<vector>
#include<algorithm>
#define ll long long
#define lcm(x,y) x*y/__gcd(x,y)
using namespace std;
const ll N=100010;
vector<int> a[N];
ll n,x,y,w[N],ans,size[N],lim[N];
void dp(ll x)
{
lim[x]=1;
if(w[x]) return;
ll minw=1e18,sum=0;
for(ll i=0;i<a[x].size();i++)
{
ll y=a[x][i];
dp(y);
lim[x]=lcm(lim[x],lim[y]);
minw=min(minw,w[y]);
sum+=w[y];
}
lim[x]*=a[x].size();
w[x]=minw*a[x].size()-minw*a[x].size()%lim[x];
ans+=sum-w[x];
}
int main()
{
//freopen("pylon.in","r",stdin);
//freopen("pylon.out","w",stdout);
scanf("%lld",&n);
for(ll i=1;i<=n;i++)
scanf("%lld",&w[i]);
for(ll i=1;i<n;i++)
{
ll x,y;
scanf("%lld%lld",&x,&y);
a[x].push_back(y);
}
dp(1);
printf("%lld",ans);
}