题目大意:在一棵20000个节点的树中,有50000个点的询问,对于每个询问,要求求出距离某点固定距离的任意一个点。
比赛的时候跪舔整场,算法确实不是很难,想不到 怎么破?
先求出整个树的直径,从直径的两个端点开始进行dfs,可以证明,对于任意一个点的询问,要不就是在该点到直径上的根上的某点,否则就是在直径上的点。
所以在这两次dfs中必定能找到解,否则就无解。
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<vector>
#include<memory.h>
#include<vector>
using namespace std;
#define maxn 21000
int n, m;
int ans[51000];
vector<int>G[maxn];
vector<pair<int,int> >Q[maxn];
void read() {
int u, v;
for(int i = 0 ;i < n-1;i++) {
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
}
void init() {
memset(ans,0,sizeof(ans));
for(int i = 1;i <= n;i++) {
G[i].clear();
Q[i].clear();
}
}
int far, maxdis;
int dfs(int rt,int fa,int dis) {
if(dis > maxdis) {
maxdis = dis;
far = rt;
}
int size = G[rt].size();
for(int i = 0 ;i < size ;i++) {
int son = G[rt][i];
if(son == fa)
continue;
dfs(son,rt,dis+1);
}
}
struct Stack {
int top;
int v[maxn];
void init() {
top = -1;
}
void push(int x) {
v[++ top] = x;
}
void pop() {
top --;
}
int size() {
return top;
}
int dis(int x) {
return v[top-x];
}
}ST;
void dfs2(int rt,int fa) {
int size = Q[rt].size();
ST.push(rt);
for(int i = 0 ;i < size; i++) {
int d = Q[rt][i].first;
if(0 != ans[Q[rt][i].second])
continue;
if(d <= ST.size())
ans[Q[rt][i].second] = ST.dis(d);
}
size = G[rt].size();
for(int i = 0 ;i < size; i++) {
int son = G[rt][i];
if(son == fa)
continue;
dfs2(son,rt);
}
ST.pop();
}
void solve() {
maxdis = -1;
dfs(1,-1,0);
int a = far;
maxdis = -1;
dfs(a,-1,0);
int b = far;
ST.init();
dfs2(a,-1);
ST.init();
dfs2(b,-1);
}
void query() {
int u, d;
for(int i = 0 ;i < m;i++) {
scanf("%d%d",&u,&d);
Q[u].push_back(make_pair(d,i));
}
}
void ANS() {
for(int i = 0 ;i < m;i++)
printf("%d\n",ans[i]);
cout << endl;
}
int main() {
while(cin >> n >> m) {
init();
read();
query();
solve();
ANS();
}
return 0;
}