zoukankan      html  css  js  c++  java
  • 【图论】TarjanLCA算法

    算法的原理:把dfs的点分为三类:

    vis[u]=0 表示这个点从未访问
    vis[u]=1 表示这个点在栈中,是u点的祖先
    vis[u]=2 表示这个点已经退栈

    Tarjan算法把lca(x,y)的查询丢给x和y的查询数组记录。后序遍历,总是会先遍历y再遍历x,那么vis[y]=2,要么x是y的祖先,要么是x的某个祖先是y的祖先。这里套个并查集加速一下,对于每个退栈的节点,把它(以及它的子树当然也是退栈了的)合并到其父亲上,那么在查询y在并查集中的代表元素中,会恰好查到还在栈中的那个最深的x的祖先,这个恰好就是lca了。

    const int MAXN = 200000 + 10;
    const int MAXM = 2000000 + 10;
    int n, m;
    vi G[MAXN];
    
    int vis[MAXN];
    int fa[MAXN];
    int ans[MAXN];
    struct Query {
        int x, y, id;
    } query[MAXN];
    
    void Init() {
        for(int i = 1; i <= n; ++i) {
            G[i].clear();
            vis[i] = 0;
            fa[i] = 0;
        }
        for(int i = 1; i <= n - 1; ++i) {
            int u, v;
            G[u].eb(v);
            G[v].eb(u);
        }
    }
    
    void dfs(int u) {
        vis[u] = 1;
        for(int v : G[u]) {
            if(vis[v])
                continue;
            dfs(v);
            fa[v] = u;
        }
        for(Query q : query[u]) {
            int x = q.x, y = q.y, id = q.id;
            if(vis[y] == 2) {
                int lca = getFa(y);
                ans[id] = lca;
            }
        }
        vis[u] = 2;
    }
    

    上面这个算法的并查集是普通的路径压缩,复杂度没变(但是很难卡,常数很小)。可以另外对每个连通块维护一个真根信息,然后改成按秩合并。(但是这太蠢了)。

    仔细一看觉得这个甚至比倍增LCA还要更好写一些?倍增LCA可以找x和y路径上的最小值,Tarjan怎么找呢。zzq大佬教了我233,啊啊啊是zzq大佬的本人啊。

    zzq大佬指出并查集可以反向维护信息,虽然是把v合并到父亲u的连通块中,但是在并查集中节点x维护的信息并不是连通块的信息,只是x这个点往上走的出栈的边的信息(注意这个只是一个临时值,不能直接使用,在路径压缩的时候一次全部合并完)。

    也就是在退栈之后,某条链是 x-3->y-2->z-1->a这样的形式,查询x到a的最小值,就在路径压缩的时候把变成 x-1->a y-1->a z-1->a 这个格式。

    那么就把询问操作不再从x处回答(否则要做正反两次tarjan),而是延迟到lca(x,y)处回答,此时x和y都分别从自己的路径上连接到了lca(x,y),路径压缩x和y后,回答info[x]和info[y]。但是,这样不是演自己吗?相信我,倍增吧。

  • 相关阅读:
    暑假练习:游戏
    Floyd算法 笔记 C/C++
    Bellman-Ford 与 SPFA 算法笔记
    Dijkstra算法 C++
    C/C++ 并查集及其优化笔记整理
    C/C++ 哈夫曼树与哈夫曼编码
    判断是否为同一颗搜索树 C/C++
    C/C++ 平衡二叉树笔记(AVL树)
    VB中 “实时错误“3704”,对象关闭时,不允许操作”
    SQL Server 2014 配置全过程
  • 原文地址:https://www.cnblogs.com/purinliang/p/14284957.html
Copyright © 2011-2022 走看看