首页 > 代码库 > tarjan解决路径询问问题

tarjan解决路径询问问题

好久没更新了,就更一篇普及组内容好了。

首先我们考虑如何用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]

tarjan解决路径询问问题