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。
题解
没有多余的路可以连的话答案就是
(n−1)×2
有一条路的话显然把最长链的两端连起来比较划算。最长链为cnt的话可以减少
cnt−1
。
如果还有一条路呢,那么我们就是找另外一条最长链,这个第二条最长链可以与第一条有重复的边,但是如果重复一条边的话就会少减少2,这样可以吧第一次最长链的边全部赋值为-1然后直接求解就好了。最长链用树形DP求。
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)) { if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)) { x = x * 10 + c - '0'; c = getchar(); }
return x * f;
}
const int N = 100000 + 10, M = 200000 + 10;
int to[M], nxt[M], val[M], hd[N], c1[N], c2[N], tot = 1;
int n, k, ans, mxp, cnt;
inline void insert(int u, int v){
to[++tot] = v; nxt[tot] = hd[u]; hd[u] = tot; val[tot] = 1;
to[++tot] = u; nxt[tot] = hd[v]; hd[v] = tot; val[tot] = 1;
}
void init(){
n = read(), k = read();
for(int i = 1; i < n; i++) insert(read(), read());
}
int dfs(int u, int fa){
int mx1 = 0, mx2 = 0;
for(int i = hd[u]; i; i = nxt[i]){
int v = to[i];
if(v != fa){
int tmp = val[i] + dfs(v, u);
if(tmp > mx1) mx2 = mx1, mx1 = tmp, c2[u] = c1[u], c1[u] = i;
else if(tmp > mx2) mx2 = tmp, c2[u] = i;
}
}
if(mx1 + mx2 > cnt) cnt = mx1 + mx2, mxp = u;
return mx1;
}
void work(){
ans = (n - 1) * 2;
dfs(1, 0); ans -= cnt - 1;
if(k == 2){
for(int i = c1[mxp]; i; i = c1[to[i]]) val[i] = val[i^1] = -1;
for(int i = c2[mxp]; i; i = c1[to[i]]) val[i] = val[i^1] = -1;
cnt = 0;
dfs(1, 0); ans -= cnt - 1;
}
printf("%d\n", ans);
}
int main(){
init();
work();
return 0;
}