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号