Description
给定一棵有n个点,m个叶子节点的树,其中m个叶子节点分别为1到m号点,每个叶子节点有一个权值r[i]。你需要给剩下n-m个点各指定一个权值,使得树上相邻两个点的权值差的绝对值之和最小。
Input
第一行包含两个正整数n,m(2<=n<=500000,1<=m<=n),分别表示点数和叶子数。
接下来n-1行,每行两个正整数u,v(1<=u,v<=n),表示u与v之间有一条边。
接下来m行,每行一个正整数,依次为r[1],r[2],…,rm,表示每个叶子的权值。
Output
输出一个整数,即树上相邻两个点的权值差的绝对值之和的最小值。
Sample Input
6 4
1 5
2 5
3 6
4 6
5 6
5
10
20
40
Sample Output
35
HINT
Source
By Claris
这题不会做..后来看了Claris题解..
大致就是拆掉叶子点,重构一下图,然后可以从孩子逆推到父亲节点的取值范围.
Claris的题解
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 500010
#define LL long long
#define GET (ch>='0'&&ch<='9')
using namespace std;
int n,m,top,tp;
int c,head=1,tail;
LL ans,sum,tmp,now;
int val[MAXN],r[MAXN],del[MAXN],q[MAXN];
int sta[MAXN<<1],cnt;
int f[MAXN],d[MAXN];
inline int abs(int x) { return x<0?-x:x; }
struct edge
{
int to;
edge *next;
}e[MAXN<<1],*prev[MAXN],E[MAXN],*Prev[MAXN];
inline void insert(int u,int v) { d[u]++;e[++top].to=v;e[top].next=prev[u];prev[u]=&e[top]; }
inline void Insert(int u,int v) { f[v]=u;E[++tp].to=v;E[tp].next=Prev[u];Prev[u]=&E[tp]; }
void in(int &x)
{
char ch=getchar();x=0;
while (!GET) ch=getchar();
while (GET) x=x*10+ch-'0',ch=getchar();
}
void dfs(int x)
{
if (!Prev[x]) return;
for (edge *i=Prev[x];i;i=i->next) dfs(i->to);
tmp=1ll<<62;sum=0;cnt=0;c=0;
for (edge *i=Prev[x];i;i=i->next) sta[++cnt]=val[i->to],sta[++cnt]=r[i->to],c--,sum+=val[i->to];
sort(sta+1,sta+cnt+1);
for (int i=1;i<=cnt;i++)
{
c++;sum-=sta[i];now=sum+1ll*sta[i]*c;
if (now<tmp) tmp=now,val[x]=sta[i];
if (now==tmp) r[x]=sta[i];
}
ans+=tmp;
}
int main()
{
in(n);in(m);int u,v;
for (int i=1;i<n;i++) in(u),in(v),insert(u,v),insert(v,u);
for (int i=1;i<=m;i++) in(val[i]),r[i]=val[i];
if (n==m)
{
for (int i=1;i<=n;i++) for (edge *j=prev[i];j;j=j->next) ans+=abs(r[i]-r[j->to]);
return printf("%lld\n",ans>>1),0;
}
for (int i=1;i<=m;i++) del[i]=1,q[++tail]=i;
while (head<=tail)
{
int last=tail;
for (int x=head;x<=tail;x++) for (edge *i=prev[q[x]];i;i=i->next) if (!del[i->to]) Insert(i->to,q[x]);
for (;head<=last;head++) for (edge *i=prev[q[head]];i;i=i->next) if (!del[i->to]&&(--d[i->to])<=1) del[i->to]=1,q[++tail]=i->to;
}
for (int i=1;i<=n;i++) if (!f[i]) Insert(0,i);
dfs(0);cout<<ans<<endl;
}