HDU4607(最大直径 树DP)

题意是给一棵树,从一个点出发走k个点,问最少走几次边。

通过一次树DP求出最大直径,如果最大直径能包含k个点就走最大直径,否则每增加一个点就需要多走一条边两次,那么答案就不难想了。

#include <bits/stdc++.h>
using namespace std;
#define maxn 511111
#define maxm 1111111

int dp[maxn][2]; //从i出发到叶子节点的最长长度 次长长度
struct node {
    int to, next;
}edge[maxm];
int n, m, head[maxn], cnt;
int Max; //最长链

void add_edge (int from, int to, int i) {
    node &e = edge[i];
    e.to = to, e.next = head[from], head[from] = i;
}

void dfs (int u, int father) {
    for (int i = head[u]; i != -1; i = edge[i].next) {
        int v = edge[i].to;
        if (v == father)
            continue;
        dfs (v, u);
        if (dp[v][0]+1 > dp[u][0]) {
            dp[u][1] = dp[u][0];
            dp[u][0] = dp[v][0]+1;
        }
        else if (dp[v][0]+1 > dp[u][1]) {
            dp[u][1] = dp[v][0]+1;
        }
    }
    Max = max (dp[u][1]+dp[u][0], Max);
}

int main () {
    //freopen ("in", "r", stdin);
    int t;
    scanf ("%d", &t);
    while (t--) {
        scanf ("%d%d", &n, &m);
        cnt = 0;
        memset (head, -1, sizeof head);
        for (int i = 1; i < n; i++) {
            int u, v;
            scanf ("%d%d", &u, &v);
            add_edge (u, v, cnt++);
            add_edge (v, u, cnt++);
        }
        Max = 0;
        memset (dp, 0, sizeof dp);
        dfs (1, 0);
        int q;
        while (m--) {
            scanf ("%d", &q);
            //cin >> q;
            if (q <= Max+1) {
                printf ("%d\n", q-1);
            }
            else {
                printf ("%d\n", Max+2*(q-Max-1));
            }
        }
    }
    return 0;
}


你可能感兴趣的:(HDU4607(最大直径 树DP))