好久没更新了,就更一篇普及组内容好了。
首先我们考虑如何用tarjan离线求出lca,伪代码大致如下:
def tarjan(x): 将x标记为已访问 for c in x的孩子: tarjan(c) 将c所在并查集的父亲置为x for q in 关于x的询问: y=询问q除了x外的另一个端点 if y已访问: q的答案=y所在并查集的根
这样为什么是对的呢?考虑lca肯定是先搜到y,再搜到x,因为此时lca还没有做完,所以此时并查集的根就是lca,而且y已经和lca并在一起了,所以会询问到正确的结果。
现在我们要用tarjan来解决路径询问问题,例如每条边有边权,若干次询问,询问路径上的边权和。
首先我们要在并查集上动一些手脚,原来并查集只是用来查询祖先,我们在并查集每个点上记一个额外信息,为这个点到并查集根的信息,在本题中即为该点到根的边权和。在查询祖先时我们可以顺便更新这个信息。
查出lca时我们把这个询问扔进lca,把它称作“延迟询问”,回到lca的时候遍历所有延迟询问,这时候x和y在并查集中的祖先都是lca,直接合并信息即可。
ff=一个初始为0的数组储存并查集 info=一个初始为空的数组储存信息 def find(x): if !ff[x]: return x y=ff[x] ff[x]=find(y) info[x]=info[x]+info[y] return ff[x] def tarjan2(x): 将x标记为已访问 for c in x的孩子: tarjan2(c) ff[c]=x info[c]=c到x的边的信息 for q in 关于x的询问: y=询问q除了x外的另一个端点 if y已访问: q的lca=y所在并查集的根 在q的lca处插入延迟询问q for q in x为lca的延迟询问: (a,b)=该询问的两个端点 find(a) find(b) q的询问结果=info[a]+info[b]
时间: 2024-10-03 21:24:02