专栏文章

题解:AT_abc428_e [ABC428E] Farthest Vertex

AT_abc428_e题解参与者 2已保存评论 1

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
1 条
当前快照
1 份
快照标识符
@minkchph
此快照首次捕获于
2025/12/02 03:49
3 个月前
此快照最后确认于
2025/12/02 03:49
3 个月前
查看原文
葬送整场比赛的题。看不懂直径的做法,来一个子树合并+换根的做法。
首先考虑处理出每一个子树 uu 内深度前两大的点,要求它们分别属于子树 v1v_1v2v_2 内(v1v_1v2v_2 均为 uu 的直接儿子,且 v1v2v_1\neq v_2)。记录它们所在的子树、它们本身的编号、距离。
定义 outmaxuoutmax_u(以下简称 omxuomx_u)代表子树 uu 以外的最远点距。从 faufa_u 转移过来。在转移时距离要 +1+1。注意也要比较 fafaufa_{fa_u} 的传递效果。这时记录两个就起到作用了,要判断自己所在的子树是否是第一大的。同样既要比距离,也要比点号大小
全程都要注意比较节点编号大小,这题我就死在 omxomx 没比较上。
时间复杂度 O(n)O(n)
CPP
#include<bits/stdc++.h>
#define int long long
#define mp(a,b) make_pair(a,b)
using namespace std;

const int N=1e6+15;
vector<int> g[N];
int n;

int fa[N];
int max1[N],max1_1[N],max1_[N];	//代表第一大的
int max2[N],max2_2[N],max2_[N];	//第二大  
//分别是距离、点号、来源子树  
void dfs(int u){
	max1[u]=0,max1_1[u]=u,max1_[u]=u;
	for(int i=0;i<g[u].size();i++){
		int v=g[u][i];
		if(fa[u]==v)	continue; 
		fa[v]=u;
		dfs(v);
		if(max1[v]+1>max1[u]||(max1[v]+1==max1[u]&&max1_1[v]>max1_1[u])){
			max2[u]=max1[u];
			max2_2[u]=max1_1[u],max2_[u]=max1_[u];
			max1[u]=max1[v]+1,max1_1[u]=max1_1[v],max1_[u]=v;
		}
		else if(max1[v]+1>max2[u]||(max1[v]+1==max2[u]&&max1_1[v]>max2_2[u])){
			max2[u]=max1[v]+1,max2_2[u]=max1_1[v],max2_[u]=v; 
		}
	} 
}
int omx[N];	//代表外面的最大距离 
int omx1[N];	//外面的最大点号  
void dfs2(int u){
	for(int i=0;i<g[u].size();i++){
		int v=g[u][i];
		if(fa[u]==v){
			//就要处理在 v 的情况 
//			for(int j=0;j<g[v].size();j++){
//				int v1=g[v][j];
//				if(fa[v]==v1)	continue;
//				if(v1!=u){
//					if(max1[u])
//				}
//			} 
			if(max1_[v]==u){
				//代表是它的最大儿子 
				omx[u]=max2[v]+1;
				omx1[u]=max2_2[v]; 
			}
			else{
				omx[u]=max1[v]+1;
				omx1[u]=max1_1[v];
			}
			if(omx[v]+1>omx[u]||(omx[v]+1==omx[u]&&omx1[v]>omx1[u])){
				omx[u]=omx[v]+1;
				omx1[u]=omx1[v];
			}
		} 
	}
	for(int i=0;i<g[u].size();i++){
		int v=g[u][i];
		if(fa[u]==v)	continue;
		dfs2(v);
	}
}
signed main(){
	cin>>n;
	for(int i=1;i<n;i++){
		int u,v;
		cin>>u>>v;
		g[u].push_back(v),g[v].push_back(u);
	}
	//对于最大点要维护的信息有:来源子树、点号 还有长度  
	dfs(1); 
	dfs2(1); 
	for(int i=1;i<=n;i++){
//		cout<<'#'<<i<<' '<<max1[i]<<' '<<max1_1[i]<<' '<<max1_[i]<<'|'<<max2[i]<<' '<<max2_2[i]<<' '<<max2_[i]<<'|'<<omx[i]<<' '<<omx1[i]<<endl;
		if((max1[i]>omx[i])||(max1[i]==omx[i]&&max1_1[i]>omx1[i])){
			cout<<max1_1[i]<<endl;
		}
		else cout<<omx1[i]<<endl;
	}
	cout<<endl;
}

评论

1 条评论,欢迎与作者交流。

正在加载评论...