专栏文章

题解:CF2062D Balanced Tree

CF2062D题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@miqdu7k5
此快照首次捕获于
2025/12/04 03:10
3 个月前
此快照最后确认于
2025/12/04 03:10
3 个月前
查看原文
感觉 D 远大于 E1,卡了好久才做出来 qwq。
先考虑怎么根据区间给点赋初值更优,由于每次子树内加相当于是两个值不同的块合并的过程,合并是必定的,所以我们应当使每次加尽可能地少加一些不必要的点。因此每个叶子节点应当取最小值,记 ava_vvv 这个点的值,对于一个点 uu,定义 k=maxvson(u)avk=\max_{v\in son(u)} a_v,则 aua_u 的取值为:
au={max(k,lu),rukru,ru<ka_u=\begin{cases}\max(k,l_u),r_u\ge k \\ r_u,r_u<k\end{cases}
现在考虑将所有点的值变成一样的过程,应该是自底向上变成一样的。对于 uuvv 的父亲,如果有 auava_u\ge a_v,那么可以通过一直加 vv 的子树变成相同的。否则就应当把 vv 作为根,将 uu 的子树一直加,直到 au=ava_u=a_v
现在考虑怎么维护这样的过程,加的过程相当于是将除了某一个子树整体加,最后统计单点的值,可以用 dfn 序加差分维护。
官方题解比我赛时写的更简单,因为最后每个点都是一样的值,所以只需要关注根节点的值,那么就变成当 av>aua_v>a_u 的时候,将根节点加上 avaua_v-a_u 了。
代码很丑,但还是放着:
CPP
#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return x*f;
}
const int maxn=2e5+20;
#define ll long long
ll t,n,val[maxn],b[maxn],cf[maxn],dfn[maxn],tot,siz[maxn],ans,f[maxn],rev[maxn];
vector<ll> e[maxn];
struct range{
	ll l,r;
}a[maxn];
void dfs(int u,int fa){
	ll flag=0,mx=0;
	dfn[u]=++tot,siz[u]=1,f[u]=fa,rev[tot]=u;
	for(int v:e[u]){
		if(v==fa) continue;
		flag=1,dfs(v,u);
		mx=max(mx,val[v]),siz[u]+=siz[v];
	}
	if(!flag) val[u]=a[u].l;
	else{
		if(mx<=a[u].r) val[u]=max(mx,a[u].l);
		else val[u]=a[u].r;
	}
}
inline void solve(){
	n=read(),tot=ans=0;
	for(int i=0;i<=n;i++) e[i].clear(),b[i]=cf[i]=0;
	int u,v;
	for(int i=1;i<=n;i++) a[i]={read(),read()};
	for(int i=1;i<n;i++) u=read(),v=read(),e[u].push_back(v),e[v].push_back(u);
	dfs(1,0);
	for(int i=1;i<=n;i++) if(f[i]&&val[i]>val[f[i]]) b[i]=val[i]-val[f[i]];
	for(int i=1;i<=n;i++) cf[0]+=b[i],cf[dfn[i]]-=b[i],cf[dfn[i]+siz[i]]+=b[i];
	for(int i=1;i<=n;i++) cf[i]+=cf[i-1],ans=max(ans,cf[i]+val[rev[i]]);
	printf("%lld\n",ans);
}
int main(){
	t=read();
	while(t--) solve();
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...