题意:
有
一
棵
n
个
点
的
树
有一棵n个点的树
有一棵n个点的树
n
−
1
条
边
经
过
每
条
边
都
需
要
1
点
体
力
n-1条边经过每条边都需要1点体力
n−1条边经过每条边都需要1点体力
给
定
一
组
u
,
v
可
以
从
u
到
v
或
者
v
到
u
不
需
要
花
费
体
力
给定一组u,v可以从u到v或者v到u不需要花费体力
给定一组u,v可以从u到v或者v到u不需要花费体力
q
次
询
问
,
x
到
y
最
少
花
费
体
力
q次询问,x到y最少花费体力
q次询问,x到y最少花费体力
题解:
n
<
=
3
e
5
,
q
<
=
1
e
6
n<=3e5,q<=1e6
n<=3e5,q<=1e6
树
上
多
次
询
问
距
离
,
L
C
A
的
经
典
题
目
树上多次询问距离,LCA的经典题目
树上多次询问距离,LCA的经典题目
预
处
理
每
个
点
的
深
度
和
他
们
的
L
C
A
预处理每个点的深度和他们的LCA
预处理每个点的深度和他们的LCA
距
离
就
是
两
点
深
度
和
减
去
他
们
L
C
A
深
度
的
二
倍
距离就是两点深度和减去他们LCA深度的二倍
距离就是两点深度和减去他们LCA深度的二倍
直
接
求
x
−
>
y
的
距
离
直接求x->y的距离
直接求x−>y的距离
然
后
求
x
−
>
u
−
>
v
−
>
y
可
能
可
以
减
少
花
费
然后求x->u->v->y可能可以减少花费
然后求x−>u−>v−>y可能可以减少花费
求
x
−
>
v
−
>
u
−
>
y
求x->v->u->y
求x−>v−>u−>y
找
最
小
值
就
是
答
案
,
每
次
都
是
一
个
l
o
g
复
杂
度
的
查
询
找最小值就是答案,每次都是一个log复杂度的查询
找最小值就是答案,每次都是一个log复杂度的查询
AC代码
/*
Author : zzugzx
Lang : C++
Blog : blog.csdn.net/qq_43756519
*/
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(), (x).end()
#define endl '\n'
#define SZ(x) (int)x.size()
#define mem(a, b) memset(a, b, sizeof(a))
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int mod = 1e9 + 7;
//const int mod = 998244353;
const double eps = 1e-6;
const double pi = acos(-1.0);
const int maxn = 1e6 + 10;
//const int N = 1e5 + 5;
const ll inf = 0x3f3f3f3f;
const int dir[][2]={{0, 1}, {1, 0}, {0, -1}, {-1, 0}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1}};
int n,depth[maxn], f[maxn][50];
int from[maxn], to[maxn << 1], nxt[maxn << 1], cnt,Log[maxn];
//链式前向星加边
void addEdge (int u, int v) {
to[++cnt] = v, nxt[cnt] = from[u], from[u] = cnt;
}
//计算深度&计算祖先
void dfs (int u, int fa) {
depth[u] = depth[fa] + 1;
for (register int i = 1; i <= Log[n]; ++i) {
if ((1 << i) > depth[u]) break;
f[u][i] = f[f[u][i - 1]][i - 1];
}
for (register int i = from[u]; i; i = nxt[i]) {
ll v = to[i];
if (v == fa) continue;
f[v][0] = u;
dfs (v, u);
}
}
//计算LCA
inline int LCA (int x, int y) {
if (depth[x] < depth[y]) swap(x, y);
//我们默认x为更深的那个点
for(register int i = Log[n] ; i >= 0 ; --i)
if(depth[x] - (1 << i) >= depth[y]) x = f[x][i];
//将x跳到和y同一深度上
if (x == y) return x;
for (register int i = Log[n]; i >= 0; --i)
if (f[x][i] != f[y][i])
x = f[x][i], y = f[y][i];
//一起向上跳
return f[x][0];
//不难看出,此时两个点均在其LCA的下方,往上跳一次即可
}
void init(){
Log[0] = -1;
cnt = 0;
for(int i = 1; i <= n; i++){
from[i] = 0,depth[i] = 0;
for(int j = 0; j < 50; j++)
f[i][j] = 0;
}
for (register int i = 1, u, v; i < n; ++i) {
cin >> u >> v;
addEdge (u, v); addEdge(v, u);
Log[i] = Log[i >> 1] + 1;
}
Log[n] = Log[n >> 1] + 1;
dfs(1,0);
}
int dis(int p , int q){return depth[p] + depth[q] - 2 * depth[LCA(p , q)];}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
cin >> n;
init();
int u, v;
cin >> u >> v;
int _;
cin >> _;
while (_--) {
int x, y;
cin >> x >> y;
int ans = dis(x, y);
ans = min(ans, dis(x, u) + dis(v, y));
ans = min(ans, dis(x, v) + dis(u, y));
cout << ans << endl;
}
return 0;
}