题解 CF2207D 【Boxed Like a Fish】

· · 题解

赛时改题面的部分道尽一切(确信)

首先不妨思考几个 naive 的情况:

注意到赛时改题面时加了一句话:but he doesn't have to do it immediately;这使我们重新审视上面这种看似简单的情况:

考虑将上面这种链的情况稍加一般化:

但这样做显然是有问题的:

不妨考虑这种最基本的反例:

借助这个反例,我们得以扩展上面的想法:

时间复杂度为 O(\sum n)

代码:

#include <stdio.h>

struct Edge {
    int nxt;
    int end;
};

int cnt;
int head[500001], dp[500001];
Edge edge[999999];

void init(int n){
    cnt = 0;
    for (int i = 1; i <= n; i++){
        head[i] = 0;
    }
}

int read(){
    int ans = 0;
    char ch = getchar();
    while (ch < '0' || ch > '9'){
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9'){
        ans = ans * 10 + (ch ^ 48);
        ch = getchar();
    }
    return ans;
}

void add_edge(int start, int end){
    cnt++;
    edge[cnt].nxt = head[start];
    head[start] = cnt;
    edge[cnt].end = end;
}

void dfs(int u, int father, int k){
    int cmin = 2e9;
    bool leaf = true;
    dp[u] = 2e9;
    for (int i = head[u]; i != 0; i = edge[i].nxt){
        int x = edge[i].end;
        if (x != father){
            leaf = false;
            dfs(x, u, k);
            if (dp[u] > dp[x] + 1){
                cmin = dp[u];
                dp[u] = dp[x] + 1;
            } else if (cmin > dp[x] + 1){
                cmin = dp[x] + 1;
            }
        }
    }
    if (leaf || dp[u] + cmin - 1 <= k) dp[u] = 0;
}

void solve(){
    int n = read(), k = read(), v = read();
    init(n);
    for (int i = 1; i < n; i++){
        int a = read(), b = read();
        add_edge(a, b);
        add_edge(b, a);
    }
    dfs(v, 0, k);
    if (dp[v] == 0){
        printf("YES\n");
    } else {
        printf("NO\n");
    }
}

int main(){
    int t = read();
    for (int cas = 1; cas <= t; cas++){
        solve();
    }
    return 0;
}