1.树上倍增
#include <queue>
#include <cstdio>
using namespace std;
const int MAXN = 1e5 + 5;
const int MAXTEP = 45;
int n, m;
int depth[MAXN], f[MAXN][MAXTEP];
int len, head[MAXN];
struct edge {
int to, next;
}e[MAXN * 2];
void add (int, int);
void build ();
int lca (int, int);
int main () {
scanf ("%d %d", &n, &m);
for (int i = 1; i < n; i++) {
int x, y; scanf ("%d %d", &x, &y);
add (x, y); add (y, x);
}
build ();
for (int i = 1; i <= m; i++) {
int x, y; scanf ("%d %d", &x, &y);
printf ("%d\n", lca (x, y));
}
return 0;
}
void add (int x, int y) {
e[++len].to = y;
e[len].next = head[x];
head[x] = len;
}
void build () {
queue <int> q; q.push (1); depth[1] = 1;
while (!q.empty ()) {
int u = q.front (); q.pop ();
for (int i = head[u]; i; i = e[i].next) {
int v = e[i].to;
if (depth[v]) continue;
depth[v] = depth[u] + 1; q.push (v);
f[v][0] = u;
for (int j = 1; j < MAXTEP; j++) {
f[v][j] = f[f[v][j - 1]][j - 1];
}
}
}
}
int lca (int x, int y) {
if (depth[x] > depth[y]) swap (x, y);
for (int i = MAXTEP - 1; i >= 0; i--) {
int v = f[y][i];
if (depth[v] >= depth[x])
y = v;
}
if (x == y) return x;
for (int i = MAXTEP - 1; i >= 0; i--) {
int v = f[x][i], vv = f[y][i];
if (v != vv)
x = v, y = vv;
}
return f[x][0];
}
2.Tarjan
#include <cstdio>
#include <iostream>
using namespace std;
const int MAXN = 1e5 + 5;
int n, m;
int fa[MAXN], vis[MAXN], ans[MAXN];
int len, head[MAXN];
struct edge {
int to, next;
}e[MAXN * 2];
int len_q, head_q[MAXN];
struct edge_q {
int to, next, index;
}e_q[MAXN * 2];
void add_e (int, int);
void add_q (int, int, int);
void Tarjan (int);
void MakeSet ();
int FindSet (int);
int main () {
cin >> n >> m; MakeSet ();
for (int i = 1; i < n; i++) {
int x, y; cin >> x >> y;
add_e (x, y); add_e (y, x);
}
for (int i = 1; i <= m; i++) {
int x, y; cin >> x >> y;
add_q (x, y, i);
add_q (y, x, i);
}
Tarjan (1);
for (int i = 1; i <= m; i++) {
printf ("%d\n", ans[i]);
}
return 0;
}
void add_e (int x, int y) {
e[++len].to = y;
e[len].next = head[x];
head[x] = len;
}
void add_q (int x, int y, int index) {
e_q[++len_q].to = y;
e_q[len_q].next = head_q[x];
e_q[len_q].index = index;
head_q[x] = len_q;
}
void Tarjan (int u) {
vis[u] = 1;
for (int i = head[u]; i; i = e[i].next) {
int v = e[i].to;
if (vis[v]) continue;
Tarjan (v);
fa[v] = u;
}
vis[u] = 2;
for (int i = head_q[u]; i; i = e_q[i].next) {
int v = e_q[i].to, index = e_q[i].index;
if (vis[v] == 2)
ans[index] = FindSet (v);
}
}
void MakeSet () {
for (int i = 1; i <= n; i++) {
fa[i] = i;
}
}
int FindSet (int x) {
if (fa[x] != x) {
fa[x] = FindSet (fa[x]);
}
return fa[x];
}