版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/liufengwei1/article/details/84489315
从一棵树取出两个点x1,x2,对于一个点x,dist[x]=min(dis[x1],dis[x2]),问这个dist[x]的最大值最小是多少。
对于一个点,他的最远点之一是某一条树的直径的端点(因为求树的直径就是随便找一个点找到任意一个最远点,把他当树的直径的端点之一)
那我们只要取出任意一条树的直径长度为a[0]放到a数组中,a[1]......a[a[0]],然后二分答案mid,那么取得点就是a[1+mid],a[a[0]-mid],因为这两个点到a[1]和a[a[0]]的长度就是mid。。然后只要从这两个点开始跑最短路看其他点是否距离<=mid就行了,显然,mid越大,越有可能使其他点都<=mid,满足二分性质。
#include<bits/stdc++.h>
#define maxl 200010
using namespace std;
int n,cnt,mxlen,mxed;
int ans,ansl,ansr;
int a[maxl],frm[maxl];
int ehead[maxl],dis[maxl];
struct ed
{
int to,nxt;
}e[maxl<<1];
bool vis[maxl];
queue <int> q;
inline void add(int u,int v)
{
e[++cnt].to=v;e[cnt].nxt=ehead[u];ehead[u]=cnt;
}
inline void prework()
{
scanf("%d",&n);
memset(ehead,0,sizeof(int)*(n+1));
int u,v;cnt=0;
for(int i=1;i<=n-1;i++)
{
scanf("%d%d",&u,&v);
add(u,v);add(v,u);
}
}
inline void dfs(int u,int fa)
{
int v;
for(int i=ehead[u];i;i=e[i].nxt)
{
v=e[i].to;
if(v==fa) continue;
dis[v]=dis[u]+1;frm[v]=u;
if(dis[v]>mxlen)
mxlen=dis[v],mxed=v;
dfs(v,u);
}
}
inline bool jug(int mid)
{
for(int i=1;i<=n;i++)
vis[i]=false,dis[i]=0;
while(!q.empty())
q.pop();
int sum=n-2,u,v;
if(1+mid!=a[0]-mid)
{
q.push(a[1+mid]),q.push(a[a[0]-mid]);
vis[a[1+mid]]=true,vis[a[a[0]-mid]]=true;
sum=n-2;
}
else
q.push(a[1+mid]),vis[a[1+mid]]=true,sum=n-1;
while(!q.empty() && dis[q.front()]<=mid)
{
u=q.front();q.pop();
for(int i=ehead[u];i;i=e[i].nxt)
{
v=e[i].to;
if(!vis[v] && dis[u]+1<=mid)
{
dis[v]=dis[u]+1;vis[v]=true;
q.push(v);sum--;
}
}
}
if(sum==0)
return true;
else
return false;
}
inline void mainwork()
{
for(int i=1;i<=n;i++)
dis[i]=0;
mxlen=0;mxed=0;
dfs(1,0);
int st=mxed,u,v;
mxlen=0;mxed=0;
for(int i=1;i<=n;i++)
dis[i]=0;
dfs(st,0);
a[0]=0;u=mxed;
while(u!=st)
{
a[++a[0]]=u;
u=frm[u];
}
a[++a[0]]=st;
int l=0,r=a[0]/2,mid;
while(l+1<r)
{
mid=(l+r)>>1;
if(jug(mid))
r=mid;
else
l=mid;
}
if(jug(l))
ans=l;
else
ans=r;
if(1+ans==a[0]-ans)
ansl=a[1+ans],ansr=a[1+ans+1];
else
ansl=a[1+ans],ansr=a[a[0]-ans];
}
inline void print()
{
printf("%d %d %d\n",ans,ansl,ansr);
}
int main()
{
//freopen("B.in","r",stdin);
int t;
scanf("%d",&t);
for(int i=1;i<=t;i++)
{
prework();
mainwork();
print();
}
return 0;
}