标签:
解题思路:
通过两次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; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:
原文地址:http://blog.csdn.net/moguxiaozhe/article/details/46953315