P4618 题解
P4618 题解
一道对笔者本人来说较难的数据结构题。
给一个比较好写的阳间做法,如有错误或笔误敬请指出,笔者将不胜感激。
题意:
给一棵节点上有颜色的有根树,要求支持两种询问,分别是给 \(u,v\),求 \(u,v\) 间路径的颜色数 \(f(u,v)\),
和给 \(A,B\),求 \(\sum\limits_{u\in S(A)}\sum\limits_{v\in S(B)}f(u,v)\),其中 \(S(A)\) 是点 \(A\) 到根的路径上的所有点形成的点集。
保证树的形态,是一条长链加若干个深度不超过 \(\log n\) 的子树接在链上,保证颜色随机。
做法:
我们对树进行 dfs
,并同时维护一个时刻 \(t\),每当第一次访问某个节点,或一个节点对应子树的访问结束后,
都将时刻加一,并记录:每个节点被第一次访问时的时刻,以及每个节点对应子树的访问完全结束后的时刻。
记节点 \(u\) 被第一次访问时的时刻是 \(st_u\),其子树内所有节点都访问后时刻为 \(en_u\)。
同时,为了方便下文描述,我们称 \(st_u\) 为 \(u\) 的入栈时刻,称 \(en_u\) 为 \(u\) 的出栈时刻。
那考虑以整棵树的访问时刻为下标,写出一个 \(2n\times 2n\) 的矩阵 \(W\),这个矩阵的每个点的权对应一条路径的答案。
其中,对于每对点 \((u,v)\),记 \((u,v)\) 路径上的颜色数为 \(f(u,v)\),则在矩阵上有 \(4\) 个点的权值与之对应,分别是:
\(W_{st_u,st_v}=W_{en_u,en_v}=f(u,v),W_{st_u,en_v}=W_{en_u,st_v}=-f(u,v)\),其中 \(W_{x,y}\) 是矩阵 \(W\) 中点 \((x,y)\) 的权值。
考虑构建矩阵 \(W\) 的好处,即对于询问 \(X(A,B)=\sum\limits_{u\in S(A)}\sum\limits_{v\in S(B)}f(u,v)\) 的值,其答案可以在矩阵上找到,
具体的,\(X(A,B)\) 的值一定等于 \(\sum\limits_{1\le i\le st_A}\sum\limits_{1\le j\le st_B}W_{i,j}\),我们可以利用 \(st\) 和 \(en\) 的性质来证明这一点,即:
考虑对于任意一点 \(u\),不难证明:点 \(v\in S(u)\) 等价于 \(st_v<st_u<en_v\),那么考虑询问 \(X(A,B)\),
我们考虑证明,所有 \(f(u,v)\) 对 \(X(A,B)\) 的贡献和其对 \(\sum\limits_{1\le i\le st_A}\sum\limits_{1\le j\le st_B}W_{i,j}\) 的贡献是一致的,
从而证明 \(X(A,B)=\sum\limits_{1\le i\le st_A}\sum\limits_{1\le j\le st_B}W_{i,j}\)。以下将会把 \(f(u,v)\) 分成四种情况讨论。
第一种是 \(u\in S(A),v\in S(B)\),显然此时 \(f(u,v)\) 给 \(X(A,B)\) 提供了恰 \(1\) 次贡献,
而由条件可得 \(st_u<st_A<en_u,st_v<st_B<en_v\),
故 \(f(u,v)\) 在 \(\sum\limits_{1\le i\le st_A}\sum\limits_{1\le j\le st_B}W_{i,j}\) 中恰好被累加了一次。
第二种是 \(u\in S(A),v\notin S(B)\),显然此时 \(f(u,v)\) 不会给 \(X(A,B)\) 提供贡献,
而由条件可得 \(st_u<st_A<en_u\),以及:\(st_B<st_v\) 或 \(st_B>en_v\) 的两者之一成立,
若 \(st_B<st_v\) 成立,则 \(f(u,v)\) 在 \(\sum\limits_{1\le i\le st_A}\sum\limits_{1\le j\le st_B}W_{i,j}\) 中显然没有被累加,即贡献为 \(0\);
若 \(st_B>en_v\) 成立,则在 \(\sum\limits_{1\le i\le st_A}\sum\limits_{1\le j\le st_B}W_{i,j}\) 中,有 \(W_{st_u,st_v}=f(u,v),W_{st_u,en_v}=-f(u,v)\),总贡献也为 \(0\)。
第三种是 \(u\notin S(A),v\in S(B)\),这种情况和第二种情况类似,就不再赘述;
第四种是 \(u\notin S(A),v\notin S(B)\),显然此时 \(f(u,v)\) 不会给 \(X(A,B)\) 提供贡献,
而由条件可得,\(st_B<st_u\) 或 \(st_B>en_u\) 的两者之一成立,以及 \(st_B<st_v\) 或 \(st_B>en_v\) 的两者之一成立,
对四种小情况分别讨论一下,也能证明 \(f(u,v)\) 在 \(\sum\limits_{1\le i\le st_A}\sum\limits_{1\le j\le st_B}W_{i,j}\) 中的贡献是正确的,这里就也不赘述了。
经过了漫长而恶心的分类讨论,我们证明了 \(X(A,B)=\sum\limits_{1\le i\le st_A}\sum\limits_{1\le j\le st_B}W_{i,j}\),
故我们可以通过快速查询矩阵 \(W\) 的二维前缀和,来回答形如 \(X(A,B)=\sum\limits_{u\in S(A)}\sum\limits_{v\in S(B)}f(u,v)\) 的询问。
为了查询前缀和,我们考虑维护每种颜色的点对 \(W\) 的贡献,即考虑该颜色对 \(W\) 中哪些位置的值造成了影响。
注意,\(W_{a,b}\) 受颜色 \(c\) 影响,当且仅当:存在 \(x\),满足点 \(x\) 的颜色为 \(c\),且 \(W_{a,b}\) 受点 \(x\) 影响,
而 \(W_{a,b}\) 受点 \(x\) 影响,当且仅当:
对于满足 \(W_{a,b}=\pm f(s,t)\) 的无序点对 \((s,t)\)(显然这样的点对唯一),路径 \((s,t)\) 包含点 \(x\)。
这样定义的原因也是好理解的,即若 \(W_{a,b}\) 受颜色 \(c\) 影响,则 \(W_{a,b}\) 的权值本身一定受到了颜色 \(c\) 的贡献。
那么,对于每种颜色 \(c\),我们希望能刻画出:\(W\) 中所有被颜色 \(c\) 影响的位置所共有的特征,
以便于维护出,颜色 \(c\) 给 \(W\) 的权值所带来的贡献。
因为颜色 \(c\) 的影响即为所有颜色为 \(c\) 的点的影响的累加,故先考虑刻画出 \(W\) 中所有被点 \(x\) 影响的位置的特征。
具体的,对于每个点 \(x\),我们考虑一个所有包含该点的路径 \((u,v)\) 所共有的性质,即:
\(u,v\) 中至少有一个点在 \(x\) 子树内,且对 \(x\) 的每个儿子 \(y\),都满足 \(u,v\) 不同时在 \(y\) 子树内。
容易发现,这个性质足够充分,即满足该特点的路径都包含点 \(x\)。
考虑用每个点的入栈时刻和出栈时刻来书写这个性质,即:
-
\(st_x<st_u<en_u<en_x\) 和 \(st_x<st_v<en_v<en_x\),两者中至少满足一个;
-
对 \(x\) 的每个儿子 \(y\),\(st_y<st_u<en_u<en_y\) 和 \(st_y<st_v<en_v<en_y\),两者最多满足一个。
显然,这两条限制同时满足,与路径 \((u,v)\) 包含点 \(x\) 等价,也就与 \(W_{st_u/en_u,st_v/en_v}\) 受点 \(x\) 影响等价,
而这两条限制勾勒出的受影响位置集,在矩阵 \(W\) 中有直观的表达方式,即:
第一个限制,形如在 \(W\) 中框出两个长方形,分别是 \([1,2n]\times [st_x,en_x]\) 和 \([st_x,en_x]\times[1,2n]\),
表示受影响位置不在这两个长方形外,其中 \([a,b]\times[c,d]\),是左下角为 \((a,c)\),右上角为 \((b,d)\) 的长方形;
第二个限制,形如在 \(W\) 中框出若干个正方形,其中对 \(x\) 的每个儿子 \(y\),都框出 \([st_y,en_y]\times[st_y,en_y]\),
表示受影响区域不在这些正方形内。那么,在排除了这些不在的区域后,剩下的所有区域就是该点的影响区域,
而一个颜色的影响区域,就等于所有该颜色的点的影响区域取并,
而我们现在需要做的,就是给这些影响区域的并区域,添加上当前颜色带来的 \(1\) 的贡献。
考虑取并的麻烦之处在于,某个点的不可行区域可能是另外一个点的可行区域,这导致了判断可行的困难性,
但实际上我们发现,对于一个固定的点 \(x\) 和其任意儿子 \(y\),以下关系永远成立:
\(([st_y,en_y]\times[st_y,en_y])\subseteq ([1,2n]\times [st_x,en_x])\cap([st_x,en_x]\times[1,2n])\);
同时,对 \(x\) 的两个儿子 \(y_1,y_2\),以下关系永远成立:
\([st_{y_1},en_{y_1}]\times[st_{y_1},en_{y_1}]\cap[st_{y_1},en_{y_1}]\times[st_{y_1},en_{y_1}]=\varnothing\)。
这两条关系利用 \(x,y_1,y_2\) 在树上的关系就不难证明,而这说明了,对于一个点影响区域的两种限制中,
第二种限制的所有禁止区域一定在第一种限制的两个允许区域的交之内,且任意两个第二种限制的禁止区域无交。
那么,记状态 \(S(x)_{i,j}\) 代表 \(W_{i,j}\) 是否受点 \(x\) 影响,我们对下标在 \([1,2n]\times [st_x,en_x]\) 中的 \(S(x)\) 值全部加一,
对下标在 \([st_x,en_x]\times[1,2n]\) 中的 \(S(x)\) 值全部加一,以及 \(x\) 的每个儿子 \(y\),
对 \([st_y,en_y]\times[st_y,en_y]\) 中的 \(S(x)\) 值全部减二,那么 \(W_{i,j}\) 受 \(x\) 影响,当且仅当这样操作后,\(S(x)_{i,j}>0\)。
上面的断言,用我们发现的两条关系就不难证明,且我们发现,这种方法在对多个点的影响取并时也同样适用,
具体的,对每种颜色 \(c\) 记 \(S'(c)_{i,j}=\sum\limits_{color(x)=c}S(x)_{i,j}\),则颜色 \(c\) 对 \(W_{i,j}\) 有影响,当且仅当 \(S'(c)_{i,j}>0\)。
那么,我们将找 \(W\) 中所有受颜色 \(c\) 影响的位置,转化为了找 \(S'(c)\) 中所有值大于 \(0\) 的位置,
且 \(S'(c)\) 的构造方式是,从空矩阵开始,对若干个矩形做区间加 / 减操作,
且这样的区间加 / 减操作次数一定不多,因为树由一条长链加若干个随机树拼接而成,故每个点的儿子数较小,
同时每个节点的颜色也是随机的,故同颜色的节点数也较小,
故我们可以把所有区间加 / 减对应矩形的横纵坐标离散化,再对离散化后的 \(S'(c)\) 暴力的维护修改操作,
最后枚举每个离散化后的位置 \(S'(c)_{i,j}\),若其值大于 \(0\),则其离散化前对应的矩形中的所有位置 \((i,j)\),
都满足 \(W_{i,j}\) 受颜色 \(c\) 影响。
那么,现在剩下的最后一个问题就是,对于颜色 \(c\) 和 \(W\) 中的某个全受颜色 \(c\) 影响的矩形区域 \([l_1,r_1]\times[l_2,r_2]\),
我们如何快速为这个矩形区域中的所有值,添加上颜色 \(c\) 带来的贡献,
且在若干次这样的操作后,我们需要能快速查询 \(W\) 的二维前缀和。
注意,这里的添加贡献,不是指全部加,而是有些位置加,有些位置减,
原因是 \(W\) 的定义,即某些 \(W_{i,j}\) 值等于 \(f(u,v)\),而另外一些 \(W_{i,j}\) 值等于 \(-f(u,v)\),具体在下文有提到。
这个问题的难点在于,对于受影响区域 \([l_1,r_1]\times[l_2,r_2]\) 中的所有位置中,有些位置需要加一,有些需要减一,
而不是全部加或全部减,所以直接对一个矩形添加贡献是难做的,但我们可以考虑每次添加贡献对查询的影响。
具体的,由于贡献的可减性,我们可以将对一个矩形加贡献,转化为对 \(4\) 个前缀矩形加 / 减贡献,
那么问题转化为,对于每个询问,维护所有前缀添加 \(v\)(\(v\) 可以为负)贡献的操作,对该询问的影响。
考虑对于一个前缀添加 \(v\) 贡献的操作,哪些位置 \((i,j)\) 的 \(W_{i,j}\) 的值实际上需要减 \(v\),
我们发现,当且仅当 \(i,j\) 中恰有一个数,在整棵树的访问时刻中是某个点的出栈时刻时,
\(W_{i,j}\) 的值实际上需要减 \(v\),其他的 \(W_{i,j}\) 的值实际上都需要加 \(v\)。
也就是说,对于一次查询 \(W\) 中前缀矩形 \([1,a]\times[1,b]\) 的前缀和的询问,
以及一次对 \(W\) 中前缀 \([1,i]\times[1,j]\) 添加 \(v\) 贡献的操作,
仅当 \(i\le a\) 且 \(j\le b\) 时,该次添加贡献的操作对该次询问有影响。
现在继续讨论影响的具体值,其中:设在时刻区间 \([i,a]\) 中有 \(p\) 个时刻是某个点的入栈时刻,
有 \(q\) 个时刻是某个点的出栈时刻;同时,设在时刻区间 \([j,b]\) 中有 \(r\) 个时刻是某个点的入栈时刻,
有 \(w\) 个时刻是某个点的出战时刻,则该次添加贡献的操作,对当前询问的贡献就是:\((pr-pw-qr+qw)v\)。
上面的断言不难证明,利用我们对添贡献操作中,具体哪些位置加,具体哪些位置减的分析即可证明其正确性,
而注意到贡献的式子实际上等于 \((p-q)(r-w)v\),而 \(p-q\) 仅与 \(i,a\) 有关,\(r-w\) 仅与 \(j,b\) 有关,
且两者都具有区间可减性,故我们可以将两者分别表示成 \(s(a)-s(i-1)\),\(s(b)-s(j-1)\) 的形式,
其中 \(s(x)\) 代表时刻 \(x\) 之前的所有时刻中,入栈时刻的数量与出栈时刻数量的差。
所以,上面的贡献式也就等于 \((s(a)-s(i-1))(s(b)-s(j-1))v\),这时再将式子中的括号拆开,就是:
\(s(a)s(b)v-s(a)s(i-1)v-s(j-1)s(b)v+s(i-1)s(j-1)v\)。
那么,对于一个询问 \([1,a]\times[1,b]\),其答案就是所有添加贡献的操作对其的影响和,即:
\(answer=\sum\limits_{([1,i]\times[1,j],v)\in Modify}(s(a)s(b)v-s(a)s(i-1)v-s(j-1)s(b)v+s(i-1)s(j-1)v)\),
其中 \(([1,i]\times[1,j],v)\in Modify\) 的含义是,存在一次对前缀 \([1,i]\times[1,j]\) 添加 \(v\) 贡献的操作,
由于长度限制,下文用 \(01\) 变量 \(M\),来代替 \(([1,i]\times[1,j],v)\in Modify\) 的值,
也用二元组 \(([1,i]\times [1,j],v)\),来代替一次对前缀 \([1,i]\times[1,j]\) 添加 \(v\) 贡献的操作。
那么,我们将上面式子的每一项拆开,即:
\(answer=\sum\limits_{M}(s(a)s(b)v)-\sum\limits_M(s(a)s(i-1)v)-\sum\limits_M(s(j-1)s(b)v)+\sum\limits_M(s(i-1)s(j-1)v)\),
有了这个式子,我们就可以将所有询问操作和添加贡献操作都离线下来,再用扫描线树状数组维护即可。
具体的,我们以 \(-\sum\limits_Ms(a)s(i-1)v\) 这一项的维护方法为例,
注意到 \(s(a)\) 的值不随操作 \(([1,i]\times[1,j],v)\) 的变化而改变,故可以将式子写成 \(-s(a)\sum\limits_Ms(i-1)v\),
而 \(\sum\limits_Ms(i-1)v\) 的值就容易维护了,我们可以将其理解为,在平面上有若干个带权的点,其中:
点 \((i,j)\) 存在,当且仅当存在操作 \(([1,i]\times[1,j],v)\),而若存在的话,此时该点权值就是 \(s(i-1)v\),
那么 \(\sum\limits_Ms(i-1)v\) 的值,就等于平面中 \([1,a]\times[1,b]\) 这片区域里,所有点点权的和,
相信看到这里的人肯定都会做了,而其他三项的维护方法,也和这个类似。
这道题就做完了,时间复杂度是 \(O(n\log n)\),但我不太会证,想要了解的话可以看 Claris
的题解。
代码较其他做法来说还算好写,就不全贴在这里了,想看的话可以点击链接。
参考文章:
Claris
的题解,链接在上面。