欧拉序求 LCA
https://www.luogu.com.cn/problem/P3379
记 \(first(x)\) 为 \(x\) 在欧拉序中第一次出现的位置,则
\[first(LCA(u,v)) = \min\{first(k)\mid k\in euler[first(u)\cdots first(v)]\}
\]
于是变成了 \(rmq\) 问题,使用 \(st\) 表即可.
时间复杂度:预处理 \(\mathcal{O}(n\log n)\),单次查询 \(\mathcal{O}(1)\).
//author:kzssCCC
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int INF = 1e9;
void solve(){
int n,q,s;
cin >> n >> q >> s;
vector<vector<int>> adj(n+1);
for (int i=0;i<n-1;i++){
int u,v;
cin >> u >> v;
adj[u].push_back(v);
adj[v].push_back(u);
}
vector<int> euler{0};
function<void(int,int)> dfs = [&](int u,int par){
euler.push_back(u);
for (auto& v:adj[u]){
if (v==par) continue;
dfs(v,u);
euler.push_back(u);
}
};
dfs(s,-1);
vector<int> first(n+1,INF);
int m = euler.size()-1;
for (int i=1;i<=m;i++){
first[euler[i]] = min(first[euler[i]],i);
}
vector<int> lg(m+1);
for (int i=2;i<=m;i++){
lg[i] = lg[i>>1]+1;
}
int K = lg[m];
vector<vector<int>> st(m+1,vector<int>(K+1));
for (int i=1;i<=m;i++){
st[i][0] = euler[i];
}
for (int k=1;k<=K;k++){
int len = 1<<k;
int half = len>>1;
for (int i=1;i+len-1<=m;i++){
st[i][k] = first[st[i][k-1]]<first[st[i+half][k-1]]?st[i][k-1]:st[i+half][k-1];
}
}
auto query = [&](int l,int r){
int len = r-l+1;
int k = lg[len];
return first[st[l][k]]<first[st[r-(1<<k)+1][k]]?st[l][k]:st[r-(1<<k)+1][k];
};
while (q--){
int x,y;
cin >> x >> y;
cout << query(min(first[x],first[y]),max(first[x],first[y])) << '\n';
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t = 1;
// cin >> t;
while (t--) solve();
return 0;
}

浙公网安备 33010602011771号