Description
Input
第一行包含两个整数 n, K(1 ≤ K ≤ 2)。接下来 n – 1行,每行两个整数 a, b, 表示村庄a与b之间有一条道路(1 ≤ a, b ≤ n)。
Output
输出一个整数,表示新建了K 条道路后能达到的最小巡逻距离。
Sample Input
8 1
1 2
3 1
3 4
5 3
7 5
8 5
5 6
Sample Output
11
HINT
10%的数据中,n ≤ 1000, K = 1;
30%的数据中,K = 1;
80%的数据中,每个村庄相邻的村庄数不超过 25;
90%的数据中,每个村庄相邻的村庄数不超过 150;
100%的数据中,3 ≤ n ≤ 100,000, 1 ≤ K ≤ 2。
我们很容易发现,这张图是一棵树。所以若k=1,即要建一条边时,就会建成一个环。在环上每一条边都只走一次即可,所以我们要使环尽量的大,我们直接找出树的最长链,将两端连起即可。
那么如果k=2呢?我们可以再找一个环,如果某条边同时出现在两个环里,那么这条边依旧要走两遍;如果这条边只出现在一个环里,则只需要走一遍即可。所以我们发现在建第二条边时,原来第一个环里的边起到的是负作用。所以我们先把第一遍环上的边全赋值为-1,然后再找一遍最长链即可。
#include<bits/stdc++.h>
using namespace std;
int read(){
char c;int x;while(c=getchar(),c<'0'||c>'9');x=c-'0';
while(c=getchar(),c>='0'&&c<='9') x=x*10+c-'0';return x;
}
int head[100005],s1[100005],s2[100005];
int n,k,cnt=1,dis,mx,tot;
struct node{
int to,val,nxt;
}L[200005];
void add(int x,int y){
L[++cnt].to=y;L[cnt].val=1;L[cnt].nxt=head[x];head[x]=cnt;
L[++cnt].to=x;L[cnt].val=1;L[cnt].nxt=head[y];head[y]=cnt;
}
int dfs(int x,int fa){
int mx1=0,mx2=0;
for(int i=head[x];i;i=L[i].nxt){
int to=L[i].to;
if(to==fa) continue;
int v=L[i].val+dfs(to,x);
if(v>mx1) mx2=mx1,mx1=v,s2[x]=s1[x],s1[x]=i;
else if(v>mx2) mx2=v,s2[x]=i;
}
if(mx1+mx2>dis) dis=mx1+mx2,mx=x;
return mx1;
}
int main()
{
n=read();k=read();tot=(n-1)*2;
for(int i=1;i<=n-1;i++){
int x=read(),y=read();
add(x,y);
}
dfs(1,0);tot=tot-dis+1;
if(k==2){
dis=0;
for(int i=s1[mx];i;i=s1[L[i].to]) L[i].val=L[i^1].val=-1;
for(int i=s2[mx];i;i=s1[L[i].to]) L[i].val=L[i^1].val=-1;
dfs(1,0);tot=tot-dis+1;
}
printf("%d\n",tot);
return 0;
}