zoukankan      html  css  js  c++  java
  • 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]
  • 相关阅读:
    Asp.net SignalR 实现服务端消息推送到Web端
    C#使用Quartz.NET详解
    Ubuntu 安装部署hugegraph
    chapter10.1、异常处理
    chapter13.2、SQLAlchemy
    chapter9.5、描述器
    chapter9.3、可调用对象,上下文管理
    chapter9.4、魔术方法反射
    chapter9.1、魔术方法
    chapter7.1、数据分发与队列queue
  • 原文地址:https://www.cnblogs.com/zzqsblog/p/6574856.html
Copyright © 2011-2022 走看看