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]
posted @ 2017-03-18 16:47 fjzzq2002 阅读(...) 评论(...) 编辑 收藏