lca 求两端的距离 跳步数
给一棵树 看能不能往上跳k步
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <queue>
#include <map>
#include <vector>
#include <stack>
#include <set>
#include <sstream>
#include <fstream>
#include <cmath>
#include <iomanip>
#include <bitset>
#include <unordered_map>
#include <unordered_set>
#include <random>
//#pragma GCC optimize(3,"Ofast","inline")
#define x first
#define y second
#define ios ios::sync_with_stdio(false),cin.tie(0);
#define endl '\n'
#define pb push_back
#define all(x) x.begin(),x.end()
#define all1(x) x.begin()+1,x.end()
using namespace std;
typedef unsigned long long uLL;
typedef long long LL;
typedef pair<int,int> PII;
const int N = 200010,M = 10010,INF = 0x3f3f3f3f,mod = 1e9 + 7;
const double DNF = 0x7f7f7f7f7f7f7f7f,pi = acos(-1.0),eps = 1e-6;
const long long LNF = 0x3f3f3f3f3f3f3f3f;
int n,m,k,t;
int l,r;
int h[N],e[N << 1],ne[N << 1],idx;
int fa[N][18],depth[N];
int dist[N];
void add(int a,int b)
{
e[idx] = b,ne[idx] = h[a],h[a] = idx ++;
}
void bfs()
{
queue<int> q;
for(int i = 1;i <= n;i ++) depth[i] = INF;
depth[0] = 0,depth[1] = 1;
q.push(1);
while(q.size())
{
int u = q.front();
q.pop();
for(int i = h[u];~ i;i = ne[i])
{
int j = e[i];
if(depth[j] > depth[u] + 1)
{
depth[j] = depth[u] + 1;
fa[j][0] = u;
q.push(j);
for(int k = 1;k <= 17;k ++)
fa[j][k] = fa[fa[j][k - 1]][k - 1];
}
}
}
}
int lca(int a,int b)
{
if(depth[a] < depth[b]) swap(a,b);
for(int k = 17;~ k;k --)
if(depth[fa[a][k]] >= depth[b])
a = fa[a][k];
if(a == b) return a;
for(int k = 17;~ k;k --)
if(fa[a][k] != fa[b][k])
{
a = fa[a][k];
b = fa[b][k];
}
return fa[a][0];
}
void dfs(int u,int fa)
{
for(int i = h[u];~ i;i = ne[i])
{
int j = e[i];
if(j == fa) continue;
if(dist[j] > dist[u] + 1)
{
dist[j] = dist[u] + 1;
dfs(j,u);
}
}
}
void find()//根据距离找dfs序 找到左右的儿子最远的端点
{
for(int i = 1;i <= n;i ++) dist[i] = INF;
dist[1] = 0;
dfs(1,0);
for(int i = 2;i <= n;i ++) if(dist[i] > dist[l]) l = i;
for(int i = 1;i <= n;i ++) dist[i] = INF;
dist[l] = 0;
dfs(l,0);
for(int i = 1;i <= n;i ++) if(dist[i] > dist[r]) r = i;
}
void solve(int u,int v,int anc,int k)
{
if(depth[u] - depth[anc] >= k)
{
for(int i = 17;~ i;i --) if(k >> i & 1) u = fa[u][i];
}
else
{
k = depth[u] + depth[v] - 2 * depth[anc] - k;
u = v;
for(int i = 17;~ i;i --) if(k >> i & 1) u = fa[u][i];
}
cout << u << endl;
}
int main()
{
ios;
cin >> n;
for(int i = 1;i <= n;i ++) h[i] = -1;
for(int i = 1;i < n;i ++)
{
int a, b;
cin >> a >> b;
add(a,b), add(b,a);
}
find();//找直径的两个端点
bfs();//lca
cin >> m;
while(m --)
{
int u, k, v;
cin >> u >> k;
int ancl = lca(u,l),ancr = lca(u,r);//与左端点的祖先 与右端点的祖先
cout <<"祖先是"<< ancl<< " " << ancr << endl;
if(depth[u] + depth[l] - 2 * depth[ancl] > depth[u] + depth[r] - 2 * depth[ancr]) v = l;
else v = r;//最远的端点是l
// cout<<"最远的端点是"<<v<<endl;
int anc;
if(v == l) anc = ancl;//确定了祖先 就不再求一次了
else anc = ancr;
if(depth[u] + depth[v] - 2 * depth[anc] < k) cout << -1 << endl;//如果最远的点到u点的距离很短 那就是这个点
else solve(u,v,anc,k);
}
return 0;
}