LGP2726题解

当初 mark 这道题还是因为看到是黑,感觉比较水,然后它现在掉紫了。

不过这题题解居然满了,写一篇给自己看吧。

首先我们有一个思路,就是割掉一条边,然后分别求两颗树的重心。

等等,这好像是CSP原题

但是这题并不是 CSP,所以就有了一个特殊性质:树高不大于 \(100\)

这就意味着直径最长是 \(200\),可以干一些别的事情。

首先我们知道一个性质,就是一棵树的重心一定在根节点所在的重链上。证明略。

于是就可以通过暴力跳重心 \(O(nh)\) 找到重心。

剩下部分的重心可以从 \(1\) 号节点直接跳重儿子,不过因可能因为割掉的边导致这个儿子不是重儿子,所以再维护一个次重儿子即可。割掉的边对答案的贡献知道距离后是可以 \(O(1)\) 算的,又因为我们是在树上直接移动,所以可以 \(O(1)\) 维护距离。

最终可以做到 \(O(nh)\) 的复杂度。尽管某种意义上是 \(O(n^2)\) 的。

#include<cstdio>
typedef unsigned ui;
typedef unsigned long long ull;
const ui M=50005;
ui n,dfc,cnt,d[M],L[M],R[M],h[M],f[M],son1[M],son2[M];ull ans(-1),siz[M],val1[M],val2[M],val3[M];
struct Edge{
	ui v,nx;
}e[M<<1];
inline ull min(const ull&a,const ull&b){
	return a>b?b:a;
}
inline void Add(const ui&u,const ui&v){
	e[++cnt]=(Edge){v,h[u]};h[u]=cnt;
	e[++cnt]=(Edge){u,h[v]};h[v]=cnt;
}
void DFS1(const ui&u){
	ui now(u);L[u]=++dfc;d[u]=d[f[u]]+1;
	for(ui v,E=h[u];E;E=e[E].nx)if((v=e[E].v)^f[u])f[v]=u,DFS1(v),siz[u]+=siz[v],val1[u]+=val1[v]+siz[v];
	if(siz[u]>siz[son1[f[u]]])son2[f[u]]=son1[f[u]],son1[f[u]]=u;else if(siz[u]>siz[son2[f[u]]])son2[f[u]]=u;
	R[u]=++dfc;val2[u]=val1[u];while(siz[u]<siz[son1[now]]*2)val2[u]-=siz[son1[now]]*2-siz[u],now=son1[now];
}
void DFS2(const ui&u){
	if(f[u])val3[u]=val3[f[u]]+siz[1]-siz[u]*2;for(ui E=h[u];E;E=e[E].nx)if(e[E].v^f[u])DFS2(e[E].v);
}
inline ull Find(const ui&u){
	ui now(1),dis=d[u]-1;ull v1,v2,V=val1[1]-1ull*dis*siz[u]-val1[u];
	while(true){
		if(!son1[now])break;v1=v2=-1;
		if(son1[now])v1=val3[son1[now]]-1ull*(dis+(L[son1[now]]<=L[u]&&R[u]<=R[son1[now]]?-1:1))*siz[u]-val1[u];
		if(son2[now])v2=val3[son2[now]]-1ull*(dis+(L[son2[now]]<=L[u]&&R[u]<=R[son2[now]]?-1:1))*siz[u]-val1[u];
		if(V<v1&&V<v2)break;
		if(V>=v1&&son1[now]^u)now=son1[now],V=v1,dis+=(L[now]<=L[u]&&R[u]<=R[now]?-1:1);
		if(V>=v2&&son2[now]^u)now=son2[now],V=v2,dis+=(L[now]<=L[u]&&R[u]<=R[now]?-1:1);
	}
	return V;
}
signed main(){
	ui i,u,v;scanf("%u",&n);for(i=1;i^n;++i)scanf("%u%u",&u,&v),Add(u,v);
	for(i=1;i<=n;++i)scanf("%u",siz+i);DFS1(1);val3[1]=val1[1];DFS2(1);
	for(i=2;i<=n;++i)ans=min(ans,val2[i]+Find(i));printf("%llu",ans);
}
posted @ 2022-01-11 14:58  Prean  阅读(26)  评论(0编辑  收藏  举报
var canShowAdsense=function(){return !!0};