假设树的直径的两个端点为p0,p1。如果对于一次询问(v,k)存在点q满足要求,那么q必然在v到p0或v到p1的路径上。
剩下的就是在树上寻找p了。倍增就好了。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#define LL long long
#define ULL unsigned long long
#define INF 0x3f3f3f3f
using namespace std;
const int MAXN = 20010;
const int MAXM = 15;
struct N
{
int v,next;
}edge[2*MAXN];
int head[MAXN];
int Top;
void Link(int u,int v)
{
edge[Top].v = v;
edge[Top].next = head[u];
head[u] = Top++;
}
int pa[2][MAXN][MAXM];
int dep[2][MAXN];
void InitDepFa(int s,int lay,int pre = -1,int d = 0)
{
dep[lay][s] = d;
pa[lay][s][0] = pre;
for(int p = head[s];p != -1; p = edge[p].next)
{
if(edge[p].v != pre)
InitDepFa(edge[p].v,lay,s,d+1);
}
}
void InitPa(int n,int lay)
{
int i,j;
for(j = 1;j < MAXM; ++j)
{
for(i = 1;i <= n; ++i)
{
if(pa[lay][i][j-1] != -1)
pa[lay][i][j] = pa[lay][pa[lay][i][j-1]][j-1];
else
pa[lay][i][j] = -1;
}
}
}
int QueryKthPoint(int u,int k,int lay)
{
for(int i = MAXM-1;i >= 0 && k; --i)
{
if(k >= (1<<i))
u = pa[lay][u][i],k -= (1<<i);
}
return u;
}
queue<int> q;
bool mark[MAXN];
int bfs(int s)
{
memset(mark,false,sizeof(mark));
mark[s] = true;
q.push(s);
while(q.empty() == false)
{
s = q.front();
q.pop();
for(int p = head[s] ;p != -1; p = edge[p].next)
if(mark[edge[p].v] == false)
q.push(edge[p].v),mark[s] = true;
}
return s;
}
int main()
{
int i,u,v,n,m,a,k;
while(scanf("%d %d",&n,&m) != EOF)
{
memset(head,-1,sizeof(head));
Top = 0;
for(i = 1;i < n; ++i)
{
scanf("%d %d",&u,&v);
Link(u,v);
Link(v,u);
}
u = bfs(v = bfs(1));
InitDepFa(u,0);
InitPa(n,0);
InitDepFa(v,1);
InitPa(n,1);
while(m--)
{
scanf("%d %d",&a,&k);
if(dep[0][a] >=k)
printf("%d\n",QueryKthPoint(a,k,0));
else if(dep[1][a] >= k)
printf("%d\n",QueryKthPoint(a,k,1));
else
printf("0\n");
}
}
return 0;
}