正题
题目大意
一棵树,每个叶子节点有权值,每个点的权值是它这棵子树中的所有叶子节点权值之和。可以减少叶子节点的值,要求减少最少的值使得对于每个点,它的所有子节点的权值都相等。
解题思路
如果将叶子节点的深度优先访问顺序排好,那么就是一个序列。对于这个序列,我们只可以区间减少。那么我们可以先将一个区间减到满足要求,再考虑更大的区间。
对于每个点我们先不考虑原本权值。我们对于每个点我们构建一种系数xxx。
对于第iii个点,如果它的子树已经平衡了,那么当我们将总值减去xix_ixi的倍数时它还是平衡的。
明显这个系数为limx=LCM(wsonx)lim_x=LCM(w_{son_x})limx=LCM(wsonx)
然后这个点的
wx=min{wsonx}∗son_numx+min{wsonx}∗son_numx%limxw_x=min\{w_{son_x}\}*son\_num_x+min\{w_{son_x}\}*son\_num_x\% lim_xwx=min{wsonx}∗son_numx+min{wsonx}∗son_numx%limx
codecodecode
#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);
}