LGP5992题解

贪心和DP一样,上来先找规律

考虑一种特殊情况:菊花图。

很容易发现这是小学数学题,排序后取中点。

来考虑另一种情况:深度为 3 的完全二叉树。

假设这颗完全二叉树的节点编号是按照线段树编号的,给定权值的节点是 4 5 6 7。方便起见,设 \(v_u\) 为编号为 \(u\) 的节点的权值,且有 \(v_5>v_4,v_7>v_6\)

很容易发现 \(v_3\) 取值范围是 \([v_4,v_5]\)\(v_4\) 的取值范围是 \([v_6,v_7]\)

那么 \(v_1\) 呢?

分类讨论。

  1. \(v_5 \leq v_6\) 很明显是 \([v_5,v_6]\)
  2. 两个区间相交 很明显取值范围就是区间的交。

有没有一点儿思路了?

再来看看一种情况(下面设节点 \(u\) 的取值范围是 \([l_u,r_u]\)):

节点 \(u\) 有三个儿子 \(a,b,c\),且 \(l_a \leq l_b,r_b \leq r_a,r_a \leq l_c\)(也就是 \(a\) 包含了 \(b\)

取值范围明显是 \([r_b,r_a]\)

所以最终思路是:将儿子的取值范围的左右端点全部拉出来,排序后取最中间的两个作为该节点的取值范围。

记得特判 \(n=m=2\) 的阴间情况(

#include<algorithm>
#include<cstdio>
const int M=5e5+5;
int n,m,cnt,f[M],h[M],l[M],r[M];int len,tmp[M<<1];long long ans;
struct Edge{
	int v,nx;
}e[M<<1];
inline void Add(const int&u,const int&v){
	e[++cnt]=(Edge){v,h[u]};h[u]=cnt;
	e[++cnt]=(Edge){u,h[v]};h[v]=cnt;
}
void DFS(const int&u){
	for(int v,E(h[u]);E;E=e[E].nx)if((v=e[E].v)^f[u])f[v]=u,DFS(v);
	for(int v,E(h[u]);E;E=e[E].nx)if((v=e[E].v)^f[u])tmp[++len]=l[v],tmp[++len]=r[v];
	if(!e[h[u]].nx)return;std::sort(tmp+1,tmp+len+1);l[u]=tmp[len>>1];r[u]=tmp[(len>>1)+1];len=0;
	for(int v,E(h[u]);E;E=e[E].nx)if((v=e[E].v)^f[u])ans+=l[u]>r[v]?l[u]-r[v]:l[u]<l[v]?l[v]-l[u]:0;
}
signed main(){
	int i,u,v;scanf("%d%d",&n,&m);
	for(i=1;i<n;++i)scanf("%d%d",&u,&v),Add(u,v);for(i=1;i<=m;++i)scanf("%d",&u),l[i]=r[i]=u;
	if(n==2)return!printf("%d",l[1]>l[2]?l[1]-l[2]:l[2]-l[1]);
	DFS(n);printf("%lld",ans);
}
posted @ 2022-01-11 14:39  Prean  阅读(26)  评论(0编辑  收藏  举报
var canShowAdsense=function(){return !!0};