题目大意:
给定一棵含 n ( 3 ≤ n ≤ 2 ⋅ 1 0 5 ) n\ (3\leq n\leq2\cdot 10^5) n (3≤n≤2⋅105)个结点的无权树,试找出三个结点 u u u、 v v v、 w w w。
card ( { u , v 间的路径 } ∪ { v , w 间的路径 } ∪ { w , u 间的路径 } ) \operatorname{card}(\{u,v\text{ 间的路径}\}\cup\{v,w\text{ 间的路径}\}\cup\{w,u\text{ 间的路径}\}) card({ u,v 间的路径}∪{ v,w 间的路径}∪{ w,u 间的路径})最大。
你需要输出两行:
第一行为 M A X card ( { u , v 间的路径 } ∪ { v , w 间的路径 } ∪ { w , u 间的路径 } ) MAX\operatorname{card}(\{u,v\text{ 间的路径}\}\cup\{v,w\text{ 间的路径}\}\cup\{w,u\text{ 间的路径}\}) MAXcard({
u,v 间的路径}∪{
v,w 间的路径}∪{
w,u 间的路径})
第二行三个整数,即 u u u、 v v v、 w w w,如有多种答案,输出一种即可。
题目思路:
小丑竟是我自己系列,写完以后以为是正解没想到还是偏离的,不过A掉了就可以。
看一下网上的普遍解法,求一下树的直径,因为三个点中间的两个点必然是树的直径的两个端点,然后找一个点到树的直径的距离最大即可
然后看一下小丑的解法:
首先推出一个结论,如果存在一个或者一个以上度数 ≥ 3 \ge3 ≥3的节点,那么最终答案一定会交于这个点。反之,如果没有说明树为一条链(一条链的答案很显然了)
基于答案会交于度数大于 3 3 3的点这个结论,那么就可以找三条以该点 u , ∣ d e g r e e u ≥ 3 ∣ u,|degree_u \ge 3| u,∣degreeu≥3∣为端点,然后最长的三条路径并且分别记录路径的最大值与路径的另一个端点。最后拍个序取前三大即可
怎么维护三条路径的端点及最大值 —— 树形dp + 换根就可以了
附一下小丑的代码:
Code:
/*** 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
***/