주요 아이디어 :
n (3 ≤ n ≤ 2 ⋅ 10 5) n \ (3 \ leq n \ leq2 \ cdot 10 ^ 5) 인 나무가 주어집니다.n ( 3 ≤엔≤2⋅1 05 )노드가있는 인증되지 않은 트리, 3 개의 노드 찾기uuu、vvv、www。
card ({path between u, v} ∪ {path between v, w} ∪ {path between w, u}) \ operatorname {card} (\ {u, v \ text {path} \} \ cup \ {path v, w \ text {} \} \ cup \ {w, u \ text {} \} 사이의 경로) c a r d ( { u ,v } 사이의 경로 ∪{ v ,w } 사이의 경로 ∪{ w ,u } ) 사이의 경로 가 가장 큽니다.
두 줄을 출력해야합니다.
첫 번째 줄은 MAX 카드입니다 ({path between u, v} ∪ {path between v, w} ∪ {path between w, u}) MAX \ operatorname {card} (\ {u, v \ text {between Path) \} \ cup \ {v, w \ text {경로} \} \ cup \ {w, u \ text {경로} \})M A Xc a r d ( {
u ,v } 사이의 경로 ∪{
v ,w } 사이의 경로 ∪{
w ,u 사이의 경로 } )
두 번째 줄에있는 세 개의 정수, 즉uuu、vvv、www , 답변이 여러 개인 경우 하나만 출력합니다.
질문 아이디어 :
조커는 사실 저만의 시리즈입니다. 글을 다 쓴 후 올바른 해답이라고 생각했지만 편차가있을 거라고 생각하지 않았지만 A를 떨어 뜨려도 괜찮습니다.
인터넷에서 일반적인 솔루션을보고 나무의 지름을 찾으십시오. 세 점 사이의 두 점이 나무 지름의 두 끝 점이되어야하기 때문입니다. 그런 다음 나무 지름과 가장 거리가 먼 지점을 찾으십시오.
그런 다음 광대의 해결책을 살펴보십시오.
먼저 결론을 내리십시오. 각도가 하나 이상인 경우 ≥ 3 \ ge3≥3 노드이면이 시점에서 최종 답변이 확실히 전달됩니다. 반대로 나무가 사슬이라고 명시되지 않은 경우 (사슬에 대한 답은 분명합니다)
답에 따르면 정도가 3 3 보다 큽니다.점 3 의 결론은이 점u, ∣ degreeu ≥ 3 ∣ u, | degree_u \ ge 3 |u ,∣ d e g r e e에≥3 ∣ 는 끝점, 다음 세 개의 가장 긴 경로, 경로의 최대 값과 경로의 다른 끝점을 각각 기록합니다. 마지막으로 순서를 잡고 상위 3 개
세 경로 트리 dp의 끝점과 최대 값을 유지하는 방법 + 그냥 루트 변경
광대 코드 첨부 :
암호:
/*** keep hungry and calm CoolGuang! ***/
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define dl(x) printf("%lld\n",x);
#define di(x) printf("%d\n",x);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF= 1e17+7;
const ll maxn = 2e6+700;
const ll mod= 1e9+7;
const ll up = 1e13;
const double eps = 1e-9;
const double PI = acos(-1);
template<typename T>inline void read(T &a){
char c=getchar();T x=0,f=1;while(!isdigit(c)){
if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){
x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;}
ll n,m,p;
vector<int>v[maxn];
int dp[maxn],suf[maxn],pos[maxn];
int b[maxn];
int in[maxn];
vector< pair<int,int> >g[maxn];
void dfs(int u,int fa){
pos[u] = u;
for(int e:v[u]){
if(e == fa) continue;
dfs(e,u);
if(dp[u]<dp[e]+1){
dp[u] = dp[e]+1;
pos[u] = pos[e];
}
}
}
int a = 0,bt = 0,c = 0;
int maxl = 0;
int res[5];
void work(int u,int fa){
if(u!=fa){
if(suf[u]<suf[fa]+1) suf[u] = suf[fa]+1,b[u] = b[fa];
if(g[fa][0].second != pos[u]){
if(suf[u] < g[fa][0].first+2) suf[u] = g[fa][0].first+2,b[u] = g[fa][0].second;
}
else if(g[fa].size()>1){
if(suf[u] < g[fa][1].first+2) suf[u] = g[fa][1].first+2,b[u] = g[fa][1].second;
}
}else b[u] = u;
for(int e:v[u]){
if(e == fa) continue;
work(e,u);
}
}
int main(){
int mx = 0;
read(n);
for(int i=1;i<=n-1;i++){
int x,y;read(x);read(y);
v[x].push_back(y);
v[y].push_back(x);
in[y]++;in[x]++;
}
for(int i=1;i<=n;i++) mx = max(mx,in[i]);
if(mx<=2){
printf("%lld\n",n-1);
int last = 1;
for(int i=1;i<=n;i++)
if(in[i] == 1){
printf("%d ",i);
}else last = i;
printf("%d\n",last);
}else{
dfs(1,1);
for(int i=1;i<=n;i++){
for(int x:v[i]){
if(dp[x] < dp[i])
g[i].push_back({
dp[x],pos[x]});
}
}
for(int i=1;i<=n;i++) sort(g[i].begin(),g[i].end(),greater<pair<int,int>>());
work(1,1);
for(int i=1;i<=n;i++){
for(auto &x:g[i]) x.first++;
g[i].push_back({
suf[i],b[i]});
}
for(int i=1;i<=n;i++) sort(g[i].begin(),g[i].end(),greater<pair<int,int>>());
for(int i=1;i<=n;i++){
ll sum = 0;
if(g[i].size()>=3){
for(int k=0;k<3;k++) sum += g[i][k].first;
if(maxl<sum){
maxl = sum;
for(int k=0;k<3;k++) res[k] = g[i][k].second;
}
}
}
di(maxl);
for(int i=0;i<3;i++) printf("%d ",res[i]);
printf("\n");
}
return 0;
}
/***
10
1 2
1 3
2 4
2 5
5 8
5 9
3 6
3 7
7 10
***/