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;
}