SP9942 HOLI - Holiday Accommodation
题意
给出一个 个点的带边权树,点的编号为 ,设 表示 到 的路径的长度。对于树上的每个点 ,找到另一个与 不相同的点 ,要求当 时,,即所有的 互不相同。求出 的最大值。
分析
答案涉及到路径的长度,不难想到把路径用一些可以提前算出的量表示。我们可以假设 为树根,那么任意一条路径 ( 表示 到 的距离),因此根据 互不相同的性质,有 。
显然,我们只要尽量使 最小就行了,而 在 处时 的值最小,所以我们可以思考是否存在一种方案使所有路径都经过 。
从 发出的每一条边都代表着 的一个子树,当一条路径经过 时,这条路径的两个端点处于不同的子树,所以只要使 在 的不同子树就可以了。
但是如果 的某个子树的节点数量超过 时,显然必须存在一些 都在同一子树内,于是我们的最佳 需要满足其每个子树的节点数量都不超过 ,这不就是重心的定义吗!所以最佳的 就是这棵树的重心,其使 ,故我们只需求 就是答案了。
两个 即可实现。
代码
时间复杂度 。
咦?怎么不小心成了最优解?(截止至 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;
}
                    
                
                
            
        
浙公网安备 33010602011771号