HDU 4607 Park visit (求树的直径)

解题思路:

通过两次DFS求树的直径,第一次以随意点作为起点,找到距离该点距离最远的点,则能够证明这个点一定在树的直径上,然后以该点为起点进行DFS得到的最长路就是树的直径。

最后的询问,假设K <= D + 1则能够沿着直径走,距离为K  -  1, 假设K >= D + 1。则须要走直径旁边的分支,每訪问一个点距离为2(从直径到这个点,再返回到直径上)。

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <vector>
#include <queue>
#define LL long long
using namespace std;
const int MAXN = 100000 + 10;
struct Edge
{
    int to, next;
}edge[2 * MAXN];
int tot;
int head[MAXN];
int dis[MAXN];
int N, M;
void init()
{
    tot = 0;
    memset(head, -1, sizeof(head));
}
void addedge(int u, int v)
{
    edge[tot].to = v;
    edge[tot].next = head[u];
    head[u] = tot++;
}
int dfs(int u, int pre = -1)
{
    int ans = u;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v = edge[i].to;
        if(v == pre) continue;
        dis[v] = dis[u] + 1;
        int dv = dfs(v, u);
        if(dis[ans] < dis[dv]) ans = dv;
    }
    return ans;
}
int solve(int u)
{
    dis[u] = 0;
    u = dfs(u);
    dis[u] = 0;
    return dis[dfs(u)];
}
int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d%d", &N, &M);
        init();
        int u, v;
        for(int i=1;i<N;i++)
        {
            scanf("%d%d", &u, &v);
            addedge(u, v);
            addedge(v, u);
        }
        int D = solve(1);
        for(int i=1;i<=M;i++)
        {
            int K;
            scanf("%d", &K);
            if(K <= D + 1) cout << K - 1 << endl;
            else cout << D + (K - D - 1) * 2 << endl;
        }
    }
    return 0;
}


原文地址:https://www.cnblogs.com/claireyuancy/p/6887826.html