CF1294F Three Paths on a Tree
CF1294F Three Paths on a Tree
题意翻译
给定一棵含 n\ (3\leq n\leq2\cdot 10^5)n (3≤n≤2⋅105) 个结点的无权树,试找出三个结点 uu、vv、ww,\operatorname{s.t.}s.t.
\operatorname{card}({u,v\text{ 间的路径}}\cup{v,w\text{ 间的路径}}\cup{w,u\text{ 间的路径}})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 间的路径})
第二行三个整数,即 uu、vv、ww,如有多种答案,输出一种即可。
题解:
贪心+树。
首先简单想一想能发现:答案应该是树的直径加上所有不在直径上的节点中,距离直径最长的距离。
那么只需要模拟这个过程就可以:
先两次DFS求出树的直径(记录路径长和两个端点),然后把直径上所有节点打上标记,然后枚举所有非直径上的节点,更新最大距离,就可以过了。
复杂度是\(O(n)\)级别。
代码:
#include<cstdio>
using namespace std;
const int maxn=2e5+5;
int n;
int tot,head[maxn],nxt[maxn<<1],to[maxn<<1];
int maxx,pos[4],ans;
int deep[maxn],fa[maxn];
bool v[maxn];
void add(int x,int y)
{
to[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
}
void dfs(int x,int f,int p)
{
if(p==2)
fa[x]=f;
deep[x]=deep[f]+1;
if(deep[x]>maxx)
{
maxx=deep[x];
pos[p]=x;
}
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(y==f)
continue;
dfs(y,x,p);
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
deep[0]=-1;
dfs(1,0,1);
maxx=0;
dfs(pos[1],0,2);
int x=pos[2];
while(x)
{
v[x]=1;
x=fa[x];
}
ans+=maxx;
maxx=0;
int tmp=0;
for(int i=1;i<=n;i++)
{
if(v[i])
continue;
else
{
x=i;
tmp=0;
while(!v[x])
{
x=fa[x];
tmp++;
}
if(maxx<tmp)
{
maxx=tmp;
pos[3]=i;
}
}
}
if(!maxx)
for(int i=1;i<=n;i++)
if(v[i]&&i!=pos[1]&&i!=pos[2])
{
pos[3]=i;
break;
}
ans+=maxx;
printf("%d\n%d %d %d\n",ans,pos[1],pos[2],pos[3]);
return 0;
}