先上模板~
/*
LCA(倍增法,二分搜索):rt[i][u](i<D=20) 表示u的第2^i的祖先
LCA预处理复杂度O (logn),每次询问O (logn)
DFS中要记录点的深度以及它的父亲,(dep[u] = d; rt[0][u] = fa;)
*/
int LCA(int u, int v) {
if (dep[u] < dep[v]) swap (u, v);
for (int i=0; i<D; ++i) {
if ((dep[u] - dep[v]) >> i & 1) {
u = rt[i][u];
}
}
if (u == v) return u;
for (int i=D-1; i>=0; --i) {
if (rt[i][u] != rt[i][v]) {
u = rt[i][u];
v = rt[i][v];
}
}
return rt[0][u];
}
void solve(void) {
DFS (1, -1, 0);
for (int i=1; i<D; ++i) { //init_LCA
for (int j=1; j<=n; ++j) {
rt[i][j] = rt[i-1][j] == -1 ? -1 : rt[i-1][rt[i-1][j]];
}
}
int lca = LCA (u, v);
}
/*
LCA -> RMQ: LCA (u, v) = F[id[u] <= i <= id[v]中dep[i]最小的i];
RMQ预处理复杂度O(nlogn),每次询问O (1)
(dp[N<<1][D], F[N<<1], dep[N<<1], id[N])
*/
void DFS(int u, int fa, int d, int &k) {
id[u] = k; F[k] = u; dep[k++] = d;
for (int i=head[u]; ~i; i=edge[i].nex) {
int v = edge[i].v;
if (v == fa) continue;
DFS (v, u, d + 1, k);
F[k] = u; dep[k++] = d;
}
}
int Min(int i, int j) {
return dep[i] < dep[j] ? i : j;
}
void init_RMQ(int k) {
for (int i=0; i<k; ++i) dp[i][0] = i;
for (int j=1; (1<<j)<=k; ++j) {
for (int i=1; i+(1<<j)-1<k; ++i) {
dp[i][j] = Min (dp[i][j-1], dp[i+(1<<(j-1))][j-1]);
}
}
}
int RMQ(int l, int r) {
int k = 0; while (1<<(k+1) <= r - l + 1) k++;
return Min (dp[l][k], dp[r-(1<<k)+1][k]);
}
int LCA(int u, int v) {
u = id[u]; v = id[v];
return u <= v ? F[RMQ (u, v)] : F[RMQ (v, u)];
}
/*
LCA离线处理,Tarjan算法,复杂度O (N+Q)
对询问次序按深搜时遍历到的节点顺序进行重组,并查集找祖先
ans[i]表示第i个询问的LCA
*/
void LCA(int u) {
rt[u] = u;
for (int i=head[u]; ~i; i=edge[i].nex) {
int v = edge[i].v;
if (rt[v] == -1) {
LCA (v);
rt[v] = u;
}
}
for (int i=headq[u]; ~i; i=query[i].nex) {
int v = query[i].v;
if (rt[v] != -1) {
int lca = Find (v);
ans[query[i].id] = lca;
}
}
}
推荐资源:Tarjan离线算法求LCA
POJ 1330 Nearest Common Ancestors
模版题
/************************************************
* Author :Running_Time
* Created Time :2015/10/5 星期一 15:12:31
* File Name :POJ_1330.cpp
************************************************/
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cmath>
#include <string>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <bitset>
#include <cstdlib>
#include <ctime>
using namespace std;
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
typedef long long ll;
const int N = 1e4 + 10;
const int D = 20;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const double EPS = 1e-8;
struct Edge {
int v, nex;
}edge[N<<1];
int head[N], in[N], e;
int F[N<<1], dep[N<<1], id[N];
int dp[N<<1][D];
void init(void) {
memset (head, -1, sizeof (head));
memset (in, 0, sizeof (in));
e = 0;
}
int Min(int i, int j) {
return dep[i] < dep[j] ? i : j;
}
void add_edge(int u, int v) {
edge[e] = (Edge) {v, head[u]};
head[u] = e++;
}
void DFS(int u, int fa, int d, int &k) {
id[u] = k;
F[k] = u;
dep[k++] = d;
for (int i=head[u]; ~i; i=edge[i].nex) {
int v = edge[i].v;
if (v == fa) continue;
DFS (v, u, d + 1, k);
F[k] = u;
dep[k++] = d;
}
}
void init_RMQ(int k) {
memset (dp, 0, sizeof (dp));
for (int i=0; i<k; ++i) dp[i][0] = i;
for (int j=1; (1<<j)<=k; ++j) {
for (int i=1; i+(1<<j)-1<k; ++i) {
dp[i][j] = Min (dp[i][j-1], dp[i+(1<<(j-1))][j-1]);
}
}
}
int RMQ(int l, int r) {
int k = 0; while (1<<(k+1) <= r - l + 1) k++;
return Min (dp[l][k], dp[r-(1<<k)+1][k]);
}
int LCA(int u, int v) {
u = id[u]; v = id[v];
return u <= v ? F[RMQ (u, v)] : F[RMQ (v, u)];
}
int main(void) {
int T; scanf ("%d", &T);
while (T--) {
int n; scanf ("%d", &n);
init ();
for (int u, v, i=1; i<n; ++i) {
scanf ("%d%d", &u, &v);
add_edge (u, v); in[v]++;
}
int tot = 0;
for (int i=1; i<=n; ++i) {
if (!in[i]) {
DFS (i, 0, 0, tot); break;
}
}
init_RMQ (tot);
int u, v; scanf ("%d%d", &u, &v);
printf ("%d\n", LCA (u, v));
}
return 0;
}
模版题
/************************************************
* Author :Running_Time
* Created Time :2015/10/4 星期日 18:36:06
* File Name :HDOJ_2586.cpp
************************************************/
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cmath>
#include <string>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <bitset>
#include <cstdlib>
#include <ctime>
using namespace std;
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
typedef long long ll;
const int N = 4e4 + 10;
const int M = 2e2 + 10;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const double EPS = 1e-8;
struct Edge {
int v, nex, len;
}edge[N*2];
struct Query {
int v, nex, len, id;
}query[M*2];
int head[N], headq[N], rt[N], d[N], ans[M];
int n, m, e, q;
void init(void) {
memset (head, -1, sizeof (head));
memset (headq, -1, sizeof (headq));
memset (rt, -1, sizeof (rt));
e = 0; q = 0;
}
void add_edge(int u, int v, int len) {
edge[e].v = v; edge[e].len = len;
edge[e].nex = head[u]; head[u] = e++;
}
void add_query(int u, int v, int id) {
query[q].v = v; query[q].id = id;
query[q].nex = headq[u]; headq[u] = q++;
}
int Find(int x) {
return rt[x] == x ? x : rt[x] = Find (rt[x]);
}
void LCA(int u, int len) {
d[u] = len; rt[u] = u;
for (int i=head[u]; ~i; i=edge[i].nex) {
int v = edge[i].v;
if (rt[v] == -1) {
LCA (v, len + edge[i].len);
rt[v] = u;
}
}
for (int i=headq[u]; ~i; i=query[i].nex) {
int v = query[i].v;
if (rt[v] != -1) {
int lca = Find (v);
ans[query[i].id] = d[u] + d[v] - (d[lca] << 1);
}
}
}
int main(void) {
int T; scanf ("%d", &T);
while (T--) {
init ();
scanf ("%d%d", &n, &m);
for (int u, v, len, i=1; i<n; ++i) {
scanf ("%d%d%d", &u, &v, &len);
add_edge (u, v, len);
add_edge (v, u, len);
}
for (int u, v, i=1; i<=m; ++i) {
scanf ("%d%d", &u, &v);
add_query (u, v, i);
add_query (v, u, i);
}
LCA (1, 0);
for (int i=1; i<=m; ++i) {
printf ("%d\n", ans[i]);
}
}
return 0;
}