# 用于求最近公共祖先(LCA)的 Tarjan算法–以POJ1986为例（转）

LCA Tarjan算法

LCA Tarjan基本框架：

LCA Tarjan 算法演示

(3,4) (3,5) (5,6) (6,7) (1,8)

DFS节点4,发现查询(3,4),查看visited[3],发现被访问过,应答查询(3,4),应答getf(3)=2;

LCA Tarjan 算法遍历每个点一遍,处理所有询问,时间复杂度为Θ(N+2M)

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
#define ll long long
using namespace std;
const int inf=0x3ffffff;
const int MAXN = 40010;
const int MAXM = 100008;
const double eps = 1e-6;
struct Edge{
int next, to, info;
}edge[MAXM];
struct Requst {
int next, to;
}request[MAXM];
int n, m;
int first[MAXN], cnt;
int dis[MAXN];
int father[MAXN], level[MAXN], sum[MAXN];
bool vis[MAXN];
int ans[MAXN];
int find(int x) {
if (x == father[x]) {
return x;
}
int ret = find(father[x]);
dis[x] += dis[father[x]];
return father[x] = ret;
}

void dfs(int x, int dep) {
vis[x] = true;
level[x] = dep;
for (int i = first[x]; i != -1; i = request[i].next) {
if (vis[request[i].to]) {
find(request[i].to);
ans[i/2] = dis[request[i].to] + sum[dep] - sum[level[father[request[i].to]]];
//下标是i/2的原因：在存放请求的时候，是存放两次  其中 i和i|1是一次请求
}
}
for (int i = head[x]; i != -1; i = edge[i].next) {
if (!vis[edge[i].to]) {
sum[dep+1] = sum[dep] + edge[i].info;
dfs(edge[i].to, dep+1);
dis[edge[i].to] = edge[i].info;
father[edge[i].to] = x;
}
}
}

int main() {
#ifndef ONLINE_JUDGE
freopen("1.txt", "r", stdin);
#endif
int i, j, k;
int x, y, w;
char c;
while(~scanf("%d%d", &n, &m)) {
tot = 0;
cnt = 0;
memset(vis, false, sizeof(vis));
memset(first, -1, sizeof(first));
memset(ans, 0, sizeof(ans));
memset(dis, 0, sizeof(dis));
memset(level, 0, sizeof(level));
for (i = 0; i <= n; i++) {
father[i] = i;
}
for (i = 0; i < m; i++) {
scanf("%d %d %d %c", &x, &y, &w, &c);
edge[tot].to = y;
edge[tot].info = w;
edge[tot].to = x;
edge[tot].info = w;
}
scanf("%d", &k);
for (i = 0; i < k; i++) {
scanf("%d%d", &x, &y);
request[cnt].to = y;
request[cnt].next = first[x];
first[x] = cnt++;
request[cnt].to = x;
request[cnt].next = first[y];
first[y] = cnt++;
}
sum[0] = 0;
dfs(1, 1);
for (i = 0; i < k; i++) {
printf("%d\n", ans[i]);
}
}
return 0;
}

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客