• 「学习笔记」tarjan 求最近公共祖先


    Tarjan 算法是一种 离线算法,需要使用并查集记录某个结点的祖先结点。
    并没有传说中的那么快。

    过程

    将询问都记录下来,将它们建成正向边和反向边。
    在 dfs 的过程中,给走过的节点打上标记,同时维护并查集,这里利用了回溯的思想,如果 uu 节点的这棵子树没搜完,那么 fa[u] = u;,搜完后,在更新并查集。
    我们假设查询 uuvv 的最近公共祖先,搜到节点 uu,如果另一个节点 vv 已经被搜到过了,那么 vv 点的并查集祖先就是 uuvv 的最近公共祖先。

    如果第一次查询 vv 点时,发现 vv 点已经被搜到了,说明 uuvv 点在同一棵子树中,并且这个子树是所有包括了 uu 点和 vv 点的子树中 siz 最小的,这棵子树的根也是在所有符合条件的子树的根中离 uuvv 最近的,即这棵子树的根就是 uuvv 的最近公共祖先,而 vv 的并查集祖先就是这个根节点。

    代码

    结构体记录询问

    int cnt = 1;
    
    struct query {
    	int v, lca, nxt;
    } q[N << 1];
    

    记录询问、初始化

    for (int i = 1, x, y; i <= m; ++ i) {
    	scanf("%d%d", &x, &y);
    	add_query(x, y);
    	add_query(y, x);
    }
    for (int i = 1; i <= n; ++ i) {
    	fa[i] = i;
    }
    

    tarjan、并查集

    void tarjan(int u) {
    	fa[u] = u;
    	vis[u] = 1;
    	for (int v : son[u]) {
    		if (!vis[v]) {
    			tarjan(v);
    			fa[v] = u;
    		}
    	}
    	int v;
    	for (int i = h[u]; i; i = q[i].nxt) {
    		if (vis[v = q[i].v]) {
    			q[i].lca = q[i ^ 1].lca = find(v);
    		}
    	}
    }
    

    fa[u] = u; 是为了保证在 uu 这棵子树没有搜完的情况下,让它子树里的节点的并查集找祖先时找到的是它。


    __EOF__

  • 本文作者: yi_fan0305
  • 本文链接: https://www.cnblogs.com/yifan0305/p/17364892.html
  • 关于博主: 四叶草少年
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章下方的【推荐】一下。
  • 相关阅读:
    java计算机毕业设计社交的健身网课平台服务器端源码+系统+数据库+lw文档+mybatis+运行部署
    计算机毕设(附源码)JAVA-SSM绩效考核管理系统
    日语基础复习 Day 16
    springboot整合nacos
    thinkphp6 只有默认页能访问 其他404 其他模块404
    CAD如何绘制六连环图案?CAD使用圆,椭圆,直线综合练习
    数据指标体系建设思考(一)
    XS9922A,XS9922B四路模拟高清方案
    JK触发器与模12计数器
    CS224W Colab_3 & Colab_4 笔记(用消息传递模型实现GNNConv,GraphSage和GAT)
  • 原文地址:https://www.cnblogs.com/yifan0305/p/17364892.html