• 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 }
  • 相关阅读:
    4.4 Iterator(迭代器)
    4.6 Memento(备忘录)
    4.1 Chain of Responsibility(职责链)
    4.5 Mediator(中介者)
    4.7 Observer(观察者)
    4.8 State(状态)
    4.11 Visitor(访问者)
    4.2 Command(命令)
    3.7 Proxy(代理)
    4.10 Template Method(模板方法)
  • 原文地址:https://www.cnblogs.com/fredy/p/5931260.html
Copyright © 2020-2023  润新知