找出树直径的两个端点,找出所有点到这两个点的距离。
对每一个询问。查看被询问点到两个端点距离为k的点,如果存在就输出。
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <list>
#include <deque>
#include <string>
#define LL long long
#define DB double
#define SI(a) scanf("%d",&a)
#define SD(a) scanf("%lf",&a)
#define SS(a) scanf("%s",a)
#define SF scanf
#define PF printf
#define MM(a,v) memset(a,v,sizeof(a))
#define REP(i,a,b) for(int (i)=(a);(i)<(b);(i)++)
#define REPD(i,a,b) for(int (i)=(a);(i)>(b);(i)--)
#define N 20009
#define INF 0x3f3f3f3f
#define EPS 1e-8
#define bug puts("bug")
using namespace std;
int dp1[N][16],dp2[N][16];
vector<int> L[N];
int n,q;
queue<int> que;
int dis[N];
int visit[N];
int fin(int k)
{
MM(dis,INF);
int ret;
que.push(k);
dis[k] = 0;
while(!que.empty())
{
int e = que.front();que.pop();
ret = e;
REP(i,0,(int)L[e].size())
{
int to = L[e][i];
if(dis[to]==INF)
{
dis[to] = dis[e]+1;
que.push(to);
}
}
}return ret;
}
void dfs(int k,int dp[][16])
{
REP(i,0,(int)L[k].size())
{
int to = L[k][i];
if(visit[to]) continue;
visit[to] = 1;
dp[to][0] = k;
REP(j,1,16)
{
dp[to][j] = dp[dp[to][j-1]][j-1];
if(dp[to][j]==0) break;
}
dfs(to,dp);
}
}
void ini()
{
int rt1 = fin(1);
int rt2 = fin(rt1);
MM(visit,0);
visit[rt1] = 1;
dfs(rt1,dp1);
MM(visit,0);
visit[rt2] = 1;
dfs(rt2,dp2);
}
int solve(int k,int d)
{
if(d==0) return k;
int ret = k;
REPD(i,30,-1)
{
if(d&(1<<i))
ret = dp1[ret][i];
if(ret==0) break;
}
if(ret) return ret;
ret = k;
REPD(i,30,-1)
{
if(d&(1<<i))
ret = dp2[ret][i];
if(ret==0) break;
}
return ret;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
SI(n);SI(q);
int a,b;
REP(i,1,n)
{
SI(a);SI(b);
L[a].push_back(b);
L[b].push_back(a);
}
ini();
while(q--)
{
SI(a);SI(b);
PF("%d\n",solve(a,b));
}
return 0;
}