Description
N个点N-1条无向边的组成的连通图,现在允许你删除一条边,再添加一条边,在保证连通的前提下,使得最远的两个点之间的距离尽可能小。
Input
第一行包含一个整数N(1<=N<=300000),表示点数,编号为1到N。
接下来N-1行,每行包含两个整数,表示一条边连接的两个点。
Output
第一行输出重组后的最远两个点的距离的最小值。
Sample Input
输入1:
4
1 2
2 3
3 4
输入2:
7
1 3
2 3
2 7
4 3
7 5
3 6
Sample Output
输出1:
2
输出2:
3
Hint
【数据范围】
40%的数据N<=30;
70%的数据N<=3000;
思路
首先这是一棵树
显然我们必须改变那条直径(否则答案只会变大)
所以我们枚举直径上的边把它删掉,于是他们就分成两棵树。
只要连接那两棵树的直径的中点即可。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=310000;
int st[N],en[N*2],next[N*2],fa[N],n,d[N*2],height[N],mh[N][2],f1[N],f2[N];
bool t[N];
int a[N][2];
void add(int x,int p[])
{
if (p[0]<x) p[1]=p[0],p[0]=x; else
if (p[1]<x) p[1]=x;
}
void build_tree(int root)
{
d[1]=root;
height[root]=1;
fa[root]=0;
int top=1;
for(int j=1; j<=n; j++)
{
int x=d[j];
for(int i=st[x]; i; i=next[i])
if (fa[x]!=en[i])
{
d[++top]=en[i];
height[en[i]]=height[x]+1;
fa[en[i]]=x;
}
}
memset(mh,0,sizeof(mh));
for(int i=n; i>=1; i--)
{
int x=d[i];
add(height[x],mh[x]);
add(mh[x][0],mh[fa[x]]);
}
}
int que[N*2][2];
void bfs(int cen,int po)
{
for(int i=st[cen];i;i=next[i])
if (t[en[i]]==0)
{
int top=0,tail=1,pl=1;
que[1][0]=en[i];
que[1][1]=1;
t[en[i]]=1;
if (mh[en[i]][1])
f1[po]=f2[po]=max(f1[po],mh[en[i]][0]+mh[en[i]][1]-height[en[i]]*2);
while (top<tail)
{
int now=que[++top][0],len=que[top][1];
for(int i=st[now];i;i=next[i])
if (t[en[i]]==0)
{
if (mh[en[i]][1])
f1[po]=f2[po]=max(f1[po],mh[en[i]][0]+mh[en[i]][1]-height[en[i]]*2);
que[++tail][0]=en[i];
que[tail][1]=len+1;
pl=max(pl,len+1);
t[en[i]]=1;
}
}
if (a[po][0]<pl) a[po][1]=a[po][0],a[po][0]=pl; else
if (a[po][1]<pl) a[po][1]=pl;
}
}
int pq;
void add(int x,int y)
{
next[++pq]=st[x];
st[x]=pq;
en[pq]=y;
}
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);
}
build_tree(1);
int root=1;
for(int i=1; i<=n; i++)
if (height[i]>height[root]) root=i;
build_tree(root);
t[root]=1;
int now=root,up=mh[root][0];
while (height[now]!=mh[now][0])
{
for(int i=st[now];i;i=next[i])
if (fa[now]!=en[i] && mh[en[i]][0]==mh[now][0])
{
t[en[i]]=1;
bfs(now,height[now]);
now=en[i];
break;
}
}
bfs(now,height[now]);
f1[1]=max(f1[1],a[1][0]+a[1][1]);
int ml=a[1][0];
for(int i=2; i<=up; i++)
{
ml++;
f1[i]=max(f1[i],f1[i-1]);
f1[i]=max(f1[i],max(ml,a[i][1])+a[i][0]);
ml=max(ml,a[i][0]);
}
f2[up]=max(f2[up],a[up][0]+a[up][1]);
ml=a[up][0];
for(int i=up-1; i>=1; i--)
{
ml++;
f2[i]=max(f2[i+1],f2[i]);
f2[i]=max(f2[i],max(ml,a[i][1])+a[i][0]);
ml=max(ml,a[i][0]);
}
int ans=up;
for(int i=1; i<=up-1; i++)
{
ans=min(ans,max((f1[i]+1)/2+(f2[i+1]+1)/2+1,max(f1[i],f2[i+1])));
}
printf("%d",ans);
}