【bzoj1912】[Apio2010]patrol 巡逻

题目链接

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。

题解

没有多余的路可以连的话答案就是 (n1)×2
有一条路的话显然把最长链的两端连起来比较划算。最长链为cnt的话可以减少 cnt1
如果还有一条路呢,那么我们就是找另外一条最长链,这个第二条最长链可以与第一条有重复的边,但是如果重复一条边的话就会少减少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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值