2020.02.04
LCA入门,即最小共同先祖
离线tarjan模板
#include <cstdio>
#include <cstring>
#include <cmath>
#include <ctime>
#include <cctype>
#include <algorithm>
#include <iostream>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <iomanip>
using namespace std;
#define outtime() cerr<<"User Time = "<<(double)clock()/CLOCKS_PER_SEC<<endl
#define endl "\n"
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-7;
const int N = 5e5 + 7;
int n, m, root;
vector<int> G[N];
vector<int> q[N];
vector<int> qid[N];
//int deg[N];
int fa[N], vis[N], ans[N];
int head[N], tot;
struct Edge {
int nxt, v;
Edge () {}
Edge (int nxt, int v) : nxt(nxt), v(v) {}
}edge[N << 1];
int find(int x) {
return x == fa[x]? x : fa[x] = find(fa[x]);
}
void merge(int x, int y) {
fa[find(x)] = find(y);
}
void dfs(int u, int fa) {
vis[u] = 1;
for (int i = 0; i < q[u].size(); ++i) { // 处理询问
int v = q[u][i], id = qid[u][i];
if (vis[v] == 0) continue;
ans[id] = find(v);
}
for (int i = head[u]; i != -1; i = edge[i].nxt) { // 往下处理
int v = edge[i].v;
if (v == fa) continue;
dfs(v, u);
merge(v, u);
}
}
void addedge(int u, int v) {
edge[tot] = Edge(head[u], v);
head[u] = tot++;
edge[tot] = Edge(head[v], u);
head[v] = tot++;
}
int main() {
int u, v;
scanf("%d %d %d", &n, &m, &root);
// for (int i = 1; i <= n; ++i) G[i].clear(), q[i].clear(), qid[i].clear(), deg[i] = 0, vis[i] = 0;
for (int i = 1; i <= n; ++i) fa[i] = i, head[i] = -1;
// tot = 0;
for (int i = 1; i < n; ++i) {
scanf("%d %d", &u, &v); // 存邻接表
addedge(u, v);
// deg[v]++;
}
// for (int i = 1; i <= n; ++i) { // 找根节点(入度为0)
// if (deg[i] == 0) {
// root = i;
// break;
// }
// }
for (int i = 1; i <= m; ++i) {
scanf("%d %d", &u, &v);
q[u].push_back(v); // 存询问信息
qid[u].push_back(i); // 存询问的编号
q[v].push_back(u);
qid[v].push_back(i);
}
dfs(root, 0);
for (int i = 1; i <= m; ++i) {
printf("%d\n", ans[i]);
}
return 0;
}
在线LCA
#include <cstdio>
#include <cstring>
#include <cmath>
#include <ctime>
#include <cctype>
#include <algorithm>
#include <iostream>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <iomanip>
using namespace std;
#define outtime() cerr<<"User Time = "<<(double)clock()/CLOCKS_PER_SEC<<endl
#define endl "\n"
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-7;
const int N = 1e4 + 7;
int n, deg[N], root;
vector<int> G[N];
int dep[N], par[N][20];
void dfs(int u, int fa) {
dep[u] = dep[fa] + 1;
par[u][0] = fa;
for (int i = 1; i < 20; ++i) {
par[u][i] = par[ par[u][i - 1] ][i - 1]; // 2^{i - 1} + 2^{i - 1} = 2^i
}
for (int i = 0; i < G[u].size(); ++i) {
int v = G[u][i];
if (v == fa) continue;
dfs(v, u);
}
}
int lca(int u, int v) {
if (dep[u] < dep[v]) swap(u, v);
for (int i = 19; i >= 0; --i) { // 让深度大的节点跳到和深度小的节点一样的深度
if (dep[ par[u][i] ] >= dep[v]) {
u = par[u][i];
}
}
if (u == v) return u;
for (int i = 19; i >= 0; --i) { // 两个节点一起往上跳,找到最后一个不相等的位置
if (par[u][i] != par[v][i]) {
u = par[u][i];
v = par[v][i];
}
}
return par[u][0];
}
int main() {
int t = 1;
scanf("%d", &t);
while (t--) {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) { // 初始化
G[i].clear();
deg[i] = 0;
}
int u, v;
for (int i = 1; i < n; ++i) { // 存边,加入度
scanf("%d %d", &u, &v);
G[u].push_back(v);
deg[v]++;
}
for (int i = 1; i <= n; ++i) { // 找根节点
if (deg[i] == 0) {
root = i;
break;
}
}
dfs(root, 0); // 处理深度数组和倍增数组
scanf("%d %d", &u, &v);
printf("%d\n", lca(u, v));
}
return 0;
}