http://acm.timus.ru/problem.aspx?space=1&num=1752
Consider a tree consisting of n vertices. A distance between two vertices is the minimal number of edges in a path connecting them. Given a vertex vi and distance di find a vertex ui such that distance between vi and ui equals to di.
Input
The first line contains the number of vertices n (1 ≤ n ≤ 20000) and the number of queries q (1 ≤ q ≤ 50000). Each of the following n − 1 lines describes an edge and contains the numbers of vertices connected by this edge. Vertices are numbered from 1 to n. The next q lines describe the queries. Each query is described by a line containing two numbers vi (1 ≤ vi ≤ n) and di (0 ≤ di ≤ n).
Output
You should output q lines. The i-th line should contain a vertex number ui, the answer to the i-th query. If there are several possible answers, output any of them. If there are no required vertices, output 0 instead.
题意:
树上某个点,问到她距离是k的点是哪个
tip:
找到树的直径,有结论:任意一个点到树上的最远点是直径的两个端点之一,那么k如果比这个距离远,就说明没有这个点,不然就是端点之一往上走(长度-k)或者这个点往上走k,倍增走。
直径:bfs两次,证明的话,分为相交与否两种情况反证一下
#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
const int maxn = 20000+10;
int n,m,u,v,root,high[maxn],father[maxn][25],first[maxn],tot;
bool vis[maxn];
queue<int>q;
struct node{
int v,next;
}edges[2*maxn];
void add(int u,int v){
edges[tot].v = v;edges[tot].next = first[u];first[u] = tot++;
edges[tot].v = u;edges[tot].next = first[v];first[v] = tot++;
}
void init(){
memset(first,-1,sizeof(first));
tot = 0;
for(int i = 1; i < n ; i++){
scanf("%d%d",&u,&v);
add(u,v);
}
root = 1;
}
void dfs(int root,int fa,int step){
high[root] = step;
for(int k = first[root] ; k != -1; k = edges[k].next){
if(edges[k].v == fa) continue;
father[edges[k].v][0] = root;
dfs(edges[k].v,root,step+1);
}
}
void bz(){
for(int j = 1; j <= 20 ;j++)
for(int i = 1; i<= n ;i++)
if(father[i][j-1]!=-1)
father[i][j] = father[father[i][j-1]][j-1];
else
father[i][j] = -1;
}
int bfs(){
int tmp;
while(!q.empty()){
tmp = q.front();
q.pop();
for(int k = first[tmp];k !=-1;k = edges[k].next){
if(!vis[edges[k].v]){
vis[edges[k].v] = true;
q.push(edges[k].v);
}
}
}
return tmp;
}
void sov(){
memset(vis,false,sizeof(vis));
vis[1] = true;
q.push(1);
v = bfs();
memset(vis,false,sizeof(vis));
vis[v] = true;
q.push(v);
u = bfs();
}
int fin(int a,int h){
for(int i = 0 ;i < 20 ;i++)
if((1<<i) & h) a = father[a][i];
return a;
}
int lca(int x,int y){
if(high[x] < high[y])
swap(x,y);
int dc = high[x]-high[y];
for(int i = 0 ;i < 20 ;i++)
if((1<<i) & dc) x = father[x][i];
if(x == y) return x;
for(int i = 19 ; i >= 0 ; i--)
if(father[x][i] != father[y][i]){
x = father[x][i];
y = father[y][i];
}
x = father[x][0];
return x;
}
void getq(){
for(int i = 1; i <= m ;i++){
int node,k;
scanf("%d%d",&node,&k);
int ans = -1,lun = -1,lvn = -1;
if(high[node]+high[u]-2*high[lun = lca(u,node)] >= k ){
if(high[node]-high[lun] >=k)
ans = fin(node,k);
else
ans = fin(u,high[node]+high[u]-2*high[lun]-k);
}
else if(high[node]+high[v]-2*high[lvn = lca(v,node)] >= k){
if(high[node]-high[lvn] >=k)
ans = fin(node,k);
else
ans = fin(v,high[node]+high[v]-2*high[lvn]-k);
}
else{
ans = 0;
}
printf("%d\n",ans);
}
}
int main(){
while(~scanf("%d%d",&n,&m)){
init();
sov();
dfs(1,-1,1);
bz();
getq();
}
}