LCA 最近公共祖先

人老了,学东西有点慢,学了一天,真是尴尬。

参考:http://www.cnblogs.com/wuminye/p/3525957.html 

  http://dongxicheng.org/structure/lca-rmq/

LCA算法就是求一棵有根树上两个结点(假设是S、T点)的最近的祖先。

我用的是基于 RMQ 的算法来做的。(RMQ 是什么?我迟点再补上吧。。)

这个算法的思想呢就是,把这棵树看成是一个无向图,然后求S和T之间的最短路径,然后,他们的最近公共祖先肯定在这条路上。(显而易见吧~)

然后再想想,他们的公共祖先有什么特点???是不是这条路径中深度最小的那个结点?(是不是很有道理??)

好了,深度最小,那么我们就可以直接用RMQ来查询了 ( 开什么玩笑,在树上怎么用RMQ!!!你个骗纸!!!)

是路径啊喂!!!路径就是一个数组嘛,怎么不可以RMQ了!!!!(可是怎么多路径,怎么搞啊!!!)

好了,问题来了,这么路径,怎么RMQ呢????

我们先想一下,对一棵树进行DFS的时候,顺序是怎样的?

比如上面这个图,遍历的时候

顺序应该是 A B D B E F E G E B A C A

然后深度是 0 1 2 1 2 3 2 3 2 1 0 1 0

举例:

比如 D到C的最短路径 : DBAC  在上面序列中对应的是 D B E F E G E B A C

比如D到G的最短路径:DBEG 在上面序列中对应的是 D B E F E G

都是首尾一样,中间不太一样,然后再看看深度,发现中间多的那部分,深度都没有比最近祖先更小的!!!

所以,上面这个序列就是我们想要的啊!!!! 找到起点跟终点就可以进行RMQ查询了!!!

HDOJ 2586 AC 代码

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int maxn = 1e5 + 10;
 5 // pos 存首次出现的位置  R存结点深度  idarr存遍历后的序列
 6 int pos[maxn], R[maxn], idarr[maxn<<1];
 7 bool vis[maxn];
 8 int tot, n;
 9 int rmq[maxn<<1][20], dis[maxn];
10 void ST() {
11     memset(rmq, 0, sizeof(rmq));
12     for(int i=1; i<=tot; i++) rmq[i][0] = idarr[i];
13     for(int j=1; j<20; j++) {
14         for(int i=1; i<=tot; i++) {
15             if(i+(1<<(j-1)) > tot) break;
16             int a = rmq[i][j-1], b = rmq[min(i+(1<<(j-1)), tot)][j-1];
17             rmq[i][j] = R[a] < R[b] ? a : b;
18         }
19     }
20 }
21 int query(int l, int r) {
22     int t = (int)log2(r-l+1.5);
23     int a = rmq[l][t], b = rmq[r-(1<<t)+1][t];
24     return R[a] < R[b] ? a : b;
25 }
26 struct Edge
27 {
28     int to, rev, cost;
29 };
30 std::vector<Edge> G[maxn];
31 void add(int u, int v, int cost) {
32     G[u].push_back((Edge){v, (int)G[v].size(), cost});
33     swap(u, v);
34     G[u].push_back((Edge){v, (int)G[v].size()-1, cost});
35 }
36 void dfs(int u, int dept) {
37     vis[u] = true;
38     idarr[++tot] = u;
39     pos[u] = tot;
40     R[u] = dept;
41     for(unsigned i=0; i<G[u].size(); i++) {
42         if(vis[G[u][i].to]) continue;
43         dis[G[u][i].to] = dis[u] + G[u][i].cost;
44         dfs(G[u][i].to, dept + 1);
45         idarr[++tot] = u;
46     }
47 }
48 int main() {
49     int T, m;
50     scanf("%d", &T);
51     while(T--) {
52         scanf("%d%d", &n, &m);
53         int a, b, c;
54         for(int i=1; i<n; i++) {
55             scanf("%d%d%d", &a, &b, &c);
56             add(a, b, c);
57         }
58         memset(dis, 0, sizeof(dis));
59         memset(R, 0, sizeof(R));
60         memset(vis, 0, sizeof(vis));
61         tot = 0;
62         dfs(1, 0);
63         ST();
64         while(m--) {
65             scanf("%d%d", &a, &b);
66             if(pos[a] > pos[b]) swap(a, b);
67             int t = query(pos[a], pos[b]);
68             printf("%d
", dis[a]+dis[b]-2*dis[t]);
69         }
70         for(int i=0; i<maxn; i++) G[i].clear();
71     }
72     return 0;
73 }
原文地址:https://www.cnblogs.com/fredy/p/5931260.html