分析后就是求树的直径两次bfs即可
证明:
树的直径是指树的最长简单路。求法: 两遍BFS :先任选一个起点BFS找到最长路的终点,再从终点进行BFS,则第二次BFS找到的最长路即为树的直径;
原理: 设起点为u,第一次BFS找到的终点v一定是树的直径的一个端点
证明: 1) 如果u 是直径上的点,则v显然是直径的终点(因为如果v不是的话,则必定存在另一个点w使得u到w的距离更长,则于BFS找到了v矛盾)
2) 如果u不是直径上的点,则u到v必然于树的直径相交(反证),那么交点到v 必然就是直径的后半段了
所以v一定是直径的一个端点,所以从v进行BFS得到的一定是直径长度
转自:http://www.cppblog.com/jie414341055/archive/2010/07/08/119662.html
#include <iostream> #include <cstring> #include <cstdio> #include <queue> using namespace std; struct node { int u,v; }; node edge[300005]; int first[100005],next[300005]; int d[100005]; int cc; inline void add_edge(int u,int v) { edge[cc].u=u; edge[cc].v=v; next[cc]=first[u]; first[u]=cc; cc++; edge[cc].v=u; edge[cc].u=v; next[cc]=first[v]; first[v]=cc; cc++; } int bfs(int u) { memset(d,-1,sizeof(d)); d[u]=0; queue<int> q; q.push(u); int maxx=-1; int res=0; while(!q.empty()) { u=q.front(); q.pop(); int i; for(i=first[u];i!=-1;i=next[i]) { int v=edge[i].v; if(d[v]==-1) { d[v]=d[u]+1; if(d[v]>maxx) { maxx=d[v]; res=v; } q.push(v); } } } return res; } int main() { int t; scanf("%d",&t); while(t--) { int n,m; scanf("%d%d",&n,&m); int i; memset(first,-1,sizeof(first)); cc=0; for(i=0;i<n-1;i++) { int u,v; scanf("%d%d",&u,&v); add_edge(u,v); } int u=bfs(1); int v=bfs(u); int mm=d[v]; for(i=1;i<=m;i++) { int k; scanf("%d",&k); if(k<=mm+1) { printf("%d\n",k-1); } else { printf("%d\n",mm+(k-(mm+1))*2); } } } return 0; }