zoukankan      html  css  js  c++  java
  • P6071

    从这题学到许多,故写题解以记之。(orz ix35)


    分个类:

    • (lsim r) 全是 (p) 的后代,则答案就是 (p) 到它们的 LCA 的距离;
    • 若既有后代又有祖先,答案显然是 (0)
    • 只有祖先的话,还要分两种情况:如果它们到 (p) 的路径的交是不是一条直链的话(即 LCA 不是 (p) 的祖先),那么答案就是 LCA 到 (p) 的距离;否则就是 (lsim r) 分别与 (p) 的 LCA 中最深的,下面重点讨论。

    对上面情况的判断,就是数 (p) 子树内有多少 ([l,r]) 内的节点。把子树问题转化成 dfn 就是个二维数点,由于是静态的,可以直接主席树做到 1log。

    先抛个一开始假想的时候的结论:一堆点(一个区间)的 LCA 显然可以直接线段树维护,而可以证明,若按照 dfn 排序,则答案是两端的 LCA。很可以感性理解,但也容易证明,结合虚树理论想一下就出来了。但这对做这题并没有用,直接维护区间反而好写。注意到 LCA 也是可叠加的,于是也可以用 ST 表做到 (mathrm O(1)) 查询,预处理由于次数是线对,所以需要用 (mathrm O(nlog n)-mathrm O(1)) 的欧拉序 + ST 表求 LCA。

    (lsim r) 按 dfn / 欧拉序排序后,将 (p) 也插进去,那么根据欧拉序 + ST 表求 LCA 法可知,(p) 与后继的 LCA 是与更后面节点的 LCA 的后代(越往后面取,LCA 深度越小);左边类似。于是我们只需要求 (p) 的前驱与后继。

    自然想到 2log 的树套树。考虑其本质,前驱后继其实是个变了个形的二维数点,范围是第一维是对应区间,第二维是值域上的前缀 / 后缀,运算从加法变成了求 max / min。但是这玩意没有可减性,所以树套树也是只能区间查询,而非前缀查询然后相减。幸运的是,第二维(值域维)是前缀 / 后缀,可以正反两遍对该维主席树,然后对第一维区间查询。

    但是这样太麻烦了(大雾)。前驱后继这玩意有更优秀的性质:每个点的点权就是第二维坐标。所以如果我们把第一维压扁的话,那么就不是一个复杂的 RMQ,而是直接找有值的地方,可以用类似树上二分的更简单的写法(但是区间查询的写法更为直观?)。而「有值」这玩意(即 cnt)是可减的,于是我们可以直接将左右两端两棵树相减,然后在上面二分。

    code(写老长了)

    珍爱生命,远离抄袭!
  • 相关阅读:
    苹果开发者账号多少钱?个人/公司/企业申请费用及怎么选【都有】
    uniapp ios真机调试【亲测有效】
    Uniapp---IOS打包证书私钥密码怎么获取?
    微信小程序地图计算两个点之间的距离
    各大地理坐标系互转
    解决mac下vscode等应用中vim光标无法快速移动
    python 脚本如何在后代运行并记录标准输出
    wkhtmltox 在Linux上安装
    shell中的##*,%%*问题
    matplotlib、seaborn 展示中文字体
  • 原文地址:https://www.cnblogs.com/ycx-akioi/p/solution-p6071.html
Copyright © 2011-2022 走看看