SP9942 HOLI - Holiday Accommodation

Link\text{Link}

题意

给出一个 nn 个点的带边权树,点的编号为 1n1\sim n,设 P(x,y)\text{P}(x,y) 表示 xxyy 的路径的长度。对于树上的每个点 xx,找到另一个与 xx 不相同的点 axa_x,要求当 iji\neq j 时,aiaja_i\neq a_j,即所有的 aia_i 互不相同。求出 i=1nP(i,ai)\sum_{i=1}^n \text{P}(i,a_i) 的最大值。

分析

答案涉及到路径的长度,不难想到把路径用一些可以提前算出的量表示。我们可以假设 rootroot 为树根,那么任意一条路径 P(i,j)=distidistlca(i,j)+distjdistfalca(i,j)\text{P}(i,j)=dist_i-dist_{lca(i,j)}+dist_j-dist_{fa_{lca(i,j)}}distidist_i 表示 iirootroot 的距离),因此根据 aia_i 互不相同的性质,有 i=1nP(i,ai)=2×i=1ndistii=1n(distlca(i,ai)+distfalca(i,ai))\sum_{i=1}^n \text{P}(i,a_i)=2\times\sum_{i=1}^ndist_i-\sum_{i=1}^n(dist_{lca(i,a_i)}+dist_{fa_{lca(i,a_i)}})

显然,我们只要尽量使 distlca(i,ai)dist_{lca(i,a_i)} 最小就行了,而 lca(i,ai)lca(i,a_i)rootroot 处时 distlca(i,ai)dist_{lca(i,a_i)} 的值最小,所以我们可以思考是否存在一种方案使所有路径都经过 rootroot

rootroot 发出的每一条边都代表着 rootroot 的一个子树,当一条路径经过 rootroot 时,这条路径的两个端点处于不同的子树,所以只要使 i,aii,a_irootroot 的不同子树就可以了。

但是如果 rootroot 的某个子树的节点数量超过 n2\frac{n}{2} 时,显然必须存在一些 i,aii,a_i 都在同一子树内,于是我们的最佳 rootroot 需要满足其每个子树的节点数量都不超过 n2\frac{n}{2},这不就是重心的定义吗!所以最佳的 rootroot 就是这棵树的重心,其使 i=1n(distlca(i,ai)+distfalca(i,ai))=0\sum_{i=1}^n(dist_{lca(i,a_i)}+dist_{fa_{lca(i,a_i)}})=0,故我们只需求 2×i=1ndisti2\times\sum_{i=1}^ndist_i 就是答案了。

两个 dfs\text{dfs} 即可实现。

代码

时间复杂度 O(TN)O(TN)

咦?怎么不小心成了最优解?(截止至 2022-03-18 23:08:03

#include<bits/stdc++.h>
#define ll long long
using namespace std;
long long read(){
	long long x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
const int N=1e5+10;
int t,n,sze[N],mx,port;
int head[N],nxt[N*2],ver[N*2],tot;
ll ans,edge[N*2],dist[N];
void add(int x,int y,int z){
	ver[++tot]=y;
	edge[tot]=z;
	nxt[tot]=head[x];
	head[x]=tot;
}
void dfs1(int x,int fa){
	sze[x]=1;
	int my=0;
	for(int i=head[x];i;i=nxt[i]){
		int y=ver[i];
		if(y!=fa){
			dfs1(y,x);
			sze[x]+=sze[y];
			my=max(my,sze[y]);
		}
	}
	my=max(my,n-sze[x]);
	if(my<mx){
		port=x;
		mx=my;
	}
}
void dfs2(int x,int fa){
	ans+=dist[x];
	for(int i=head[x];i;i=nxt[i]){
		int y=ver[i];
		if(y!=fa){
			dist[y]=dist[x]+edge[i];
			dfs2(y,x);
		}
	}
}
int main(){
	t=read();
	for(int ii=1;ii<=t;ii++){
		n=read();
		tot=1;
		memset(head,0,sizeof(head));
		memset(sze,0,sizeof(sze));
		memset(dist,0,sizeof(dist));
		mx=1e9;
		ans=port=0;
		for(int i=1,x,y,z;i<n;i++){
			x=read();y=read();z=read();
			add(x,y,z);add(y,x,z);
		}
		dfs1(1,0);
		dfs2(port,0);
		printf("Case #%d: %lld\n",ii,2*ans);
	}
	return 0;
}
posted @ 2022-03-18 23:13  luckydrawbox  阅读(7)  评论(0)    收藏  举报  来源