zoukankan      html  css  js  c++  java
  • 树上莫队

    树上莫队,顾名思义,就是到树上做莫队。一般会有两种写法,一种是将莫队正儿八经地搬到树上做;另一种是将莫队搬到树的括号序上做。

    树上莫队

    算法内容

    这是在树上分块跑莫队的版本。考虑到莫队的实现过程,我们需要解决两个问题:

    1. 如何对树分块,才能保证复杂度?
    2. 如何移动标记来实现转移?

    如何转移

    首先我们来解决第二个问题。

    观察序列莫队的移动方式,我们发现它其实是将区间端点暴力移动到对应的新端点上;也即,如果我们当前统计了 ((u,v)) 的答案,需要转移到 ((u',v')),那么我们可以将 (u) 暴力地移动到 (u'),将 (v) 暴力地移动到 (v'),复杂度则由分块来保证。

    定义集合的 (oplus) 运算为 (Aoplus B=Acup B-Acap B),容易验证这个运算具有交换律、结合律和归零律。

    考察一下移动过程,我们维护当前路径上的点集 (S),那么每次将指针从 (p,pin S) 移走,我们就令 (S=Soplus{p});同理,移到 (q,q otin S),我们就令 (S=Soplus{q})。所以指针的移动对点集的影响可以用 (oplus) 来描述。

    (P_{u,v})(u,v) 路径上的点组成的集合,设 (r) 为树根。不难发现 (P_{u,v}=P_{u,r}oplus P_{v,r}oplus {operatorname{LCA}(u,v)})

    (p=operatorname{LCA}(u,v),q=operatorname{LCA}(u',v')),此时我们可以很好地构造具体操作过程:

    [egin{aligned} P_{u',v'} &=P_{u,v}oplus{P_{u,v}}oplus P_{u',v'}\ &=(P_{u,r}oplus P_{v,r}oplus {p})oplus(P_{u',r}oplus P_{v',r}oplus {q})oplus P_{u,v}\ &=(P_{u,r}oplus P_{u',r})oplus (P_{v,r}oplus P_{v',r})oplus {p}oplus {q}oplus P_{u,v} end{aligned} ]

    因此我们不难看出,我们应该对于 (P_{u,u'}) 上除开 (operatorname{LCA}(u,u')) 取异或,对于 (P_{v,v'}) 上除开 (operatorname{LCA}(v,v')) 取异或,此外再对 (p,q) 分别取异或,就可以从 ((u,u')) 转移到 ((v,v'))

    如何分块

    不难发现端点在一个(不一定连通的)点集中移动的时候,单次移动复杂度取决于点集的直径。因此,我们需要保证树上的块的直径较小。设这个阈值为 (S),我们需要保证每个块的直径为 (O(S))

    一种简单的分块方法是,我们对树进行 DFS,用栈维护未被分块的点。从某个儿子回溯的时候检查当前栈中点数是否达到了 (S),如果达到了 (S) 就退栈分块;否则我们就将若干个连续遍历的儿子的块合并在一起,直到块大小达到 (S) 再分块;再不济,这些点会和当前节点合并到一个块中,并回溯到上一层。

    注意,这里需要将等待合并的儿子块从栈中拿出来,不然会破坏直径性质。


    如果我们将儿子块全部留到栈里面,那么相当于按照 DFS 序直接分块,有可能出现如下情况:

    case.png

    这样如果先遍历 (S-1) 的子树,那么这 (S-1) 个点会和 (u) 合并,导致直径过大,复杂度不正确。

    实现的时候不需要将剩余的点弹出来,在进入某个节点的时候记录当前的栈底即可。

    这样分块,能够保证每个块大致连通(最多只缺一个 LCA),同时可以保证块的大小和直径为 (O(S));并且每个点只会被包含在一个块中。

    做莫队的时候将所有询问按照左端点的块编号排序,编号相同的按照右端点的 DFS 序排序,之后按照上面所述的处理即可。


    考虑这样做的复杂度,分左端点和右端点:

    • 单个块内,左端点移动复杂度为 (O(S)),总次数为 (O(q))

      左端点换块,左端点移动复杂度为 (O(n)),总次数为 (O(frac{n}{S}))

      左端点总复杂度为 (O(qS+frac{n^2}{S}))

    • 左端点在一个块内的时候,由于右端点按照 DFS 序排序,所以右端点移动相当于对树进行 DFS 遍历,复杂度为 (O(n)),总次数为 (O(frac{n}{S})),因此复杂度为 (O(frac{n^2}{S}))

    得到复杂度为 (O(qS+frac{n^2}{S})),取 (S=sqrt{frac{n^2}{q}}) 得到最优复杂度为 (O(nsqrt{q}))

    例题

    SP10707 COT2 - Count on a tree II

    把上面说的写一遍就好了,维护不同颜色的数量毫无难度。

    括号序莫队

    待填坑

  • 相关阅读:
    【数据结构第二周】队列知识点整理
    【数据结构第二周】堆栈知识点整理
    【数据结构第二周】线性表知识点整理
    【数据结构第一周】最大子列和问题整理
    网络设置
    QT 安装教程
    C# 复制粘贴板 多行粘贴
    设置网络适配器IP优先级
    MySQL 查重复单号和删重复单号
    Mysql 10053 SocketException 你的主机中的软件中止了一个已建立的连接。
  • 原文地址:https://www.cnblogs.com/crashed/p/15135165.html
Copyright © 2011-2022 走看看