题意:在一棵树上找两个点,使其他每个点到这两个点的较大值中的最大值最小
思路:树的直径先来一发,然后找中点分树然后两棵树各找直径,两个点就是两个直径的中点(并不知道直接四等分点会怎么样,但显然不对,吧)
感觉细节还蛮多,不过代码很短。。(据说两个点不能是同一个点,反正我的似乎会自动屏蔽)
代码:
#include <bits/stdc++.h>
#define N 200009
#define gc getchar()
using namespace std;
int n,first[N],number,x,y;
int q[N],bs[N],pre[N],Far,head,tail,rt1,rt2,deep[N];
int a1,b1,a3,b3,ans;
struct edge
{
int to,next;
void add(int x,int y)
{
to=y,next=first[x],first[x]=number;
}
}e[N<<1];
int read()
{
int x=1;
char ch;
while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
int s=ch-48;
while (ch=gc,ch>='0'&&ch<='9') s=s*10+ch-48;
return x*s;
}
int bfs(int x,int y)
{
int far=0;
q[head=tail=1]=x;
memset(bs,0,sizeof(bs));
bs[x]=1;
while (head<=tail)
{
int now=q[head++];
if (bs[now]>bs[far]) far=now;
for (int i=first[now];i;i=e[i].next)
if (!bs[e[i].to]&&e[i].to!=y)
{
pre[e[i].to]=now;
bs[e[i].to]=bs[now]+1;
q[++tail]=e[i].to;
}
}
return far;
}
int get(int x,int len)
{
for (int i=1;i<=len;i++) x=pre[x];
return x;
}
int main()
{
int T=read();
while (T--)
{
n=read();
memset(first,0,sizeof(first));
number=0;
for (int i=1;i<n;i++)
{
x=read(),y=read();
e[++number].add(x,y),e[++number].add(y,x);
}
Far=bfs(bfs(1,0),0);
rt1=get(Far,(bs[Far]-1)/2);
rt2=pre[rt1];
a1=bfs(bfs(rt1,rt2),rt2);
a3=get(a1,(bs[a1]-1)/2);
ans=bs[a1]/2;
b1=bfs(bfs(rt2,rt1),rt1);
b3=get(b1,(bs[b1]-1)/2);
ans=max(ans,bs[b1]/2);
printf("%d %d %d\n",ans,a3,b3);
}
return 0;
}