当前位置: 首页 > news >正文

Tarjan算法

Tarjan算法

文章目录

  • Tarjan算法
    • Tarjan算法求LCA
      • 距离
    • 有向图的强连通分量

Tarjan算法求LCA

离线求LCA O ( n + m ) O(n + m) O(n+m)

Tarjan算法本质是使用并查集对“向上标记法”的优化。
在深度优先遍历的任意时刻,树中节点分为3类:

  1. 已经访问完毕并且回溯的节点。在这些节点标记一个整数2.
  2. 已经开始递归,但尚未回溯的节点。这些节点就是当前正在访问的节点x以及x的祖先。在这些节点上标记一个整数1.
  3. 尚未访问的节点。这些节点没有标记。

对于正在访问的节点 x x x,它到根节点的路径已经标记为1.若y是已经访问完毕并且回溯的节点,则LCA(x, y)就是从y向上走到根,第一个遇到标记为1的节点。
可以利用并查集进行优化,当一个节点获得整数2的标记时,把它所在的集合合并到它父节点所在的集合中(合并时它的父节点的标记一定为1,且单独构成一个集合)。
这相当于每个完成回溯的节点都有一个指针指向它的父节点,只需要查询y所在集合代表元素,就等价于y一直向上一直走到一个开始递归但尚未回溯的节点(标记1),即LCA(x, y)

距离

给出 n 个点的一棵树,多次询问两点之间的最短距离。

注意:

边是无向的。
所有节点的编号是 1,2,…,n。
输入格式
第一行为两个整数 n 和 m。n 表示点数,m 表示询问次数;

下来 n−1 行,每行三个整数 x,y,k,表示点 x 和点 y 之间存在一条边长度为 k;

再接下来 m 行,每行两个整数 x,y,表示询问点 x 到点 y 的最短距离。

树中结点编号从 1 到 n。

输出格式
共 m 行,对于每次询问,输出一行询问结果。

数据范围
2≤n≤104,
1≤m≤2×104,
0<k≤100,
1≤x,y≤n
输入样例1:
2 2
1 2 100
1 2
2 1
输出样例1:
100
100
输入样例2:
3 2
1 2 10
3 1 15
1 2
3 2
输出样例2:
10
25

N = 10010
M = N * 2

h = [-1] * N
e = [0] * M
w = [0] * M
ne = [-1] * M
idx = 0
dist = [0] * N
res = [0] * M
st = [0] * N
p = [0] * N
query = [[] for _ in range(N)]

def add(a, b, c) :
    global idx
    e[idx] = b
    w[idx] = c
    ne[idx] = h[a]
    h[a] = idx
    idx += 1
def find(x) :
	if x != p[x] : p[x] = find(p[x])
	return p[x]

def dfs(u, fa) : #求每个节点到根节点距离
	i = h[u]
	while ~ i :
		j = e[i]
		if j != fa : #防止回父节点
			dist[j] = dist[u] + w[i]
			dfs(j, u)
		i = ne[i]
def tarjan(u) :
	st[u] = 1
	i = h[u]
	while ~ i :
		j = e[i]
		if not st[j] : # 防止多次遍历
			tarjan(j)
			p[j] = u # 回溯完合并到此时为1的节点的集合
		i = ne[i]
	for item in query[u] :
		y, id = item[0], item[1]
		anc = find(y)
		if st[y] == 2 :
			res[id] = dist[u] + dist[y] - dist[anc] * 2
	st[u] = 2 #标记回溯

n, m = map(int, input().split())

for i in range(n - 1) :
    a, b, c = map(int, input().split())
    add(a, b, c), add(b, a, c)
    
for i in range(1, n + 1) : #初始化并查集
    p[i] = i

for i in range(m) :
    a, b = map(int, input().split())
    if a != b :
        query[a].append([b, i])
        query[b].append([a, i])

dfs(1, -1)    
tarjan(1)

for i in range(m) :
    print(res[i])

有向图的强连通分量

相关文章:

  • 网站目录做301/推广产品的文案
  • 手机版的网站用什么开发/网站注册地址查询
  • 贵阳手机网站建设/湖南网站seo地址
  • 网站建设金思扬网络/手机百度极速版app下载安装
  • 做学校网站/宁波关键词排名优化
  • 深圳网站建设app开发/汕头seo优化公司
  • python比较两张图片并获取精准度
  • Best Buy 百思买DROP SHIP EDI需求分析
  • 年度总结-你觉得什么叫生活?
  • <<零入门容器云网络实战>>技术专栏发布介绍
  • “水果零售第二股”百果园上市首日市值近百亿
  • 【OpenShift】项目上OpenShift遇到的问题总结
  • Python采集常用:谷歌浏览器驱动——Chromedriver 插件安装教程
  • WSL子系统环境下连接ssh的坑
  • Git常用命令(全局设置获取仓库)
  • python环境构造
  • 解决ElementUI导航栏重复点菜单报错问题
  • 3422. 左孩子右兄弟