欧拉序求 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;
}
posted @ 2026-07-04 13:02  kzssCCC  阅读(4)  评论(0)    收藏  举报