Time Limit: 1000MS | Memory Limit: 65536KB | 64bit IO Format: %I64d & %I64u |
Description
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
viand
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.
Sample Input
input | output |
---|---|
9 101 81 51 42 72 53 65 96 95 48 14 32 49 31 15 23 56 47 3 | 0123456789 |
题意:给出一棵树,树上两点的距离为两点路径上的边数,有q个询问,每个询问u d,要求出与u相距为d的任意一个结点。
思路:先求树的直径,得到直径上的两端点,分别以这两个端点为根能构造出两棵新的树,与任意一个点u距离为d的结点v可以在其中一棵树上通过倍增来求出。
AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
#include <vector>
#include <algorithm>
#define ll long long
using namespace std;
const int maxn = 20005;
const int INF = 1e9;
int n, q;
vector<int> G[maxn];
int to[maxn];
int dis[2][maxn], fa[maxn][2], anc[maxn][30][2];
bool vis[maxn];
int bfs(int s, int k){
queue<int> Q;
memset(vis, 0, sizeof(vis));
memset(dis[k], 0, sizeof(dis[k]));
vis[s] = 1;
Q.push(s);
int idx = s, Max = -1;
while(!Q.empty())
{
int u = Q.front();
Q.pop();
if(dis[k][u] > Max)
{
Max = dis[k][u];
idx = u;
}
for(int i = 0; i < (int) G[u].size(); i++)
{
int v = G[u][i];
if(vis[v]) continue;
vis[v] = true;
dis[k][v] = dis[k][u] + 1;
fa[v][k] = u;
Q.push(v);
}
}
for(int i = 1; i <= n; i++)
to[i] = max(to[i], dis[k][i]);
return idx;
}
void init(){
for(int k = 0; k < 2; k++)
{
for(int i = 1; i <= n; i++)
{
anc[i][0][k] = fa[i][k];
for(int j = 1; (1 << j) < n; j++)
anc[i][j][k] = -1;
}
for(int j = 1; (1 << j) < n; j++)
for(int i = 1; i <= n; i++)
if(anc[i][j - 1][k] != -1)
{
int a = anc[i][j - 1][k];
anc[i][j][k] = anc[a][j - 1][k];
}
}
}
int query(int k, int u, int d){
if(d == 0) return u;
if(d == 1) return anc[u][0][k];
int log = 1;
for(; (1 << log) <= d; log++);
log--;
for(int i = log; i >= 0; i--)
{
if(d >= (1 << i))
{
d -= (1 << i);
u = anc[u][i][k];
}
if(d == 0) return u;
}
return 0;
}
int main()
{
int a, b;
while(~scanf("%d%d", &n, &q))
{
for(int i = 1; i <= n; i++) G[i].clear();
for(int i = 0; i < n - 1; i++)
{
scanf("%d%d", &a, &b);
G[a].push_back(b);
G[b].push_back(a);
}
memset(to, 0, sizeof(to));
int s = bfs(1, 0);
int t = bfs(s, 1);
bfs(t, 0);
init();
while(q--)
{
scanf("%d%d", &a, &b);
if(to[a] < b)
{
puts("0");
continue;
}
if(dis[0][a] > dis[1][a]) printf("%d\n", query(0, a, b));
else printf("%d\n", query(1, a, b));
}
}
return 0;
}