专栏文章
AT_abc428_e 题解
AT_abc428_e题解参与者 3已保存评论 2
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 2 条
- 当前快照
- 1 份
- 快照标识符
- @minkf66b
- 此快照首次捕获于
- 2025/12/02 03:51 3 个月前
- 此快照最后确认于
- 2025/12/02 03:51 3 个月前
嗯对就是树的直径的性质。
树的直径的性质
对于树上任意一个节点 ,在所有与 存在路径的节点中,距离 最远的节点 ,必定是该树某条直径的两个端点之一。
性质的证明
采用反证法。
首先定义函数 表示 到 之间的距离。
设树的一条直径为 (即 是树中最大路径长度),任取节点 ,其最远点为 ,且 既不是 也不是 。
由于树无环,、、 三条路径必然会交于一个公共节点,记为 。根据先前定义, 且 。
因此,有 ,。由 ,可得 ,同理有 。
代入得 ,而直径 (因为 在 的路径上)。若 ,则 ,这与 “ 是树的直径” 矛盾。
代入得 ,而直径 (因为 在 的路径上)。若 ,则 ,这与 “ 是树的直径” 矛盾。
故假设不成立,因此 必须是直径 的端点,即 要么是 ,要么是 。
知道了这个东西以后,我们就可以考虑在树上使用两次 DFS 的方法求出某条直径,然后算出两个 数组,判断一下输出即可。
注意这里要求输出编号最大的节点,因此找节点的时候要注意不是随便找一个都行,是要尽可能找编号大的。
CPP#include<bits/stdc++.h>
#define LL long long
#define UInt unsigned int
#define ULL unsigned long long
#define LD long double
#define pii pair<int,int>
#define pLL pair<LL,LL>
#define fr first
#define se second
#define pb push_back
using namespace std;
const int N = 5e5+5;
int n,f[N],dis[N],St,Ed;
vector<int> g[N];
int read(){
int su=0,pp=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')pp=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){su=su*10+ch-'0';ch=getchar();}
return su*pp;
}
void DFS1(int u,int fa){
f[u]=f[fa]+1;
for(int v:g[u])
if(v^fa)DFS1(v,u);
return;
}
void DFS2(int u,int fa){
dis[u]=dis[fa]+1;
for(int v:g[u])
if(v^fa)DFS2(v,u);
return;
}
int main(){
n=read();
for(int i=1;i<n;i++){
int x=read(),y=read();
g[x].pb(y),g[y].pb(x);
}DFS1(1,0);
for(int i=1;i<=n;i++)
if(f[i]>=f[St])St=i;
memset(f,0,sizeof(f));
DFS1(St,0);
for(int i=1;i<=n;i++)
if(f[i]>=f[Ed])Ed=i;
DFS2(Ed,0);
for(int x=1;x<=n;x++)
if(f[x]>dis[x])cout<<St<<"\n";
else if(f[x]<dis[x])cout<<Ed<<"\n";
else cout<<max(St,Ed)<<"\n";
return 0;
}
如果本篇题解对你有帮助的话,麻烦你点一个小小的赞,真是太感谢啦!
相关推荐
评论
共 2 条评论,欢迎与作者交流。
正在加载评论...