【十二省联考2019】希望(容斥,换根DP,长链剖分,懒标记)

容斥 同时被 3 个专栏收录
19 篇文章 0 订阅
15 篇文章 0 订阅
11 篇文章 0 订阅

暴力的想法是考虑钦定每个点作为到达点并统计贡献,但显然这样会算重。

注意到会算重的到达点一定构成了一个连通块,这是一个很好的性质,方便了我们容斥:我们直接用点的贡献减去边的贡献(一条边的两个端点同时是到达点)即可,因为一个连通块满足点数减边数等于 1 1 1

先考虑点的贡献,需要统计以某个点为根且深度不超过 L L L 的连通块个数。

可以换根 DP:设 f u , i f_{u,i} fu,i 表示 u u u 子树内以 u u u 为根且深度不超过 i i i 的连通块个数, g u , i g_{u,i} gu,i 表示 u u u 子树外以 u u u 为根且深度不超过 i i i 的连通块个数,转移:(其中 s u s_u su 表示 u u u 的儿子集合)

f u , i = ∏ v ∈ s u ( f v , i − 1 + 1 ) g u , i = g f a , i − 1 ∏ v ∈ s f a , v ≠ u ( f v , i − 2 + 1 ) + 1 \begin{aligned} f_{u,i}&=\prod_{v\in s_u} (f_{v,i-1}+1)\\ g_{u,i}&=g_{fa,i-1}\prod_{v\in s_{fa},v\neq u}(f_{v,i-2}+1)+1 \end{aligned} fu,igu,i=vsu(fv,i1+1)=gfa,i1vsfa,v=u(fv,i2+1)+1
注意 ∏ v ∈ s f a , v ≠ u ( f v , i − 2 + 1 ) \prod\limits_{v\in s_{fa},v\neq u}(f_{v,i-2}+1) vsfa,v=u(fv,i2+1) 不能写成 f f a , i − 1 f u , i − 2 + 1 \dfrac{f_{fa,i-1}}{f_{u,i-2}+1} fu,i2+1ffa,i1,因为在模意义下有可能 f u , i − 2 + 1 f_{u,i-2}+1 fu,i2+1 0 0 0

单点贡献即为 ( f u , L ⋅ g u , L ) k (f_{u,L}\cdot g_{u,L})^k (fu,Lgu,L)k。同时单边 ( f a , u ) (fa,u) (fa,u) 的贡献也得到了,即为 ( f u , L − 1 ⋅ g u , L ) k (f_{u,L-1}\cdot g_{u,L})^k (fu,L1gu,L)k

然而暴力 DP 的复杂度为 O ( n L ) O(nL) O(nL) 的,需要优化。

先来处理 f f f,看到 f f f 的定义和深度有关,考虑用长链剖分优化:记 s o n u son_u sonu u u u 的重儿子,让 f u f_{u} fu 继承 f s o n u f_{son_u} fsonu 的信息,再从 u u u 的其他儿子 v v v 转移过来。这里下标偏移一位的问题可以用指针处理,然后全局+1可以用 add 标记处理。

但注意到 f v f_{v} fv 的数组大小范围并不是 d v d_v dv(设 d v d_v dv 表示 v v v 子树内深度最大值),而是 0 ∼ L 0\sim L 0L 都有值(根据 f f f 的定义)。

f v f_v fv 也是有特征的: f v , d v = f v , d v + 1 = ⋯ = f v , L f_{v,d_v}=f_{v,d_v+1}=\cdots =f_{v,L} fv,dv=fv,dv+1==fv,L。于是用 f v f_v fv f u f_u fu 转移时,实际上做的是前 d v + 1 d_v+1 dv+1 位暴力转移,后面的位做的是同乘 f v , d v + 1 f_{v,d_v}+1 fv,dv+1

这可以用线段树维护,但是有一个更加美妙的做法:

  • f v , d v + 1 = 0 f_{v,d_v}+1=0 fv,dv+1=0,则 f u f_u fu d v + 1 d_v+1 dv+1 位之后将一直会是 0 0 0,这可以打个 tag。
  • f v , d v + 1 ≠ 0 f_{v,d_v}+1\neq 0 fv,dv+1=0,我们打一个 f u f_u fu 全局乘 f v , d v + 1 f_{v,d_v}+1 fv,dv+1 的 tag,然后前 d v + 1 d_v+1 dv+1 位暴力转移时再乘上 f v , d v + 1 f_{v,d_v}+1 fv,dv+1 的逆。

然后就会出现很多 tag 要维护……

具体来说有以下五种:全局乘 m u l mul mul m u l mul mul 的逆元 i m u l imul imul,全局加 a d d add add(优先级在全局乘后),重置位置 l i m lim lim l i m lim lim 以后的位置都被重置),重置值 r e s e t reset reset(受全局乘和全局加影响)。

此时 f f f 就大致维护好了,时间复杂度 O ( n ) O(n) O(n)

接下来是如何维护 g g g

发现我们只需要维护 g u , L − d u ∼ g u , L g_{u,L-d_u}\sim g_{u,L} gu,Ldugu,L 的值,因为求 g u , L g_{u,L} gu,L 只需要用到 g f a , L − 1 g_{fa,L-1} gfa,L1 的值。

那么同样考虑用长链剖分优化:让 g s o n u g_{son_u} gsonu 继承 g u g_u gu 的信息,而其他儿子由 g u g_u gu 暴力转移。

现在问题是对每一个儿子 v v v 求出 ∏ v ′ ∈ s u , v ′ ≠ v ( f v ′ , i − 2 + 1 ) \prod\limits_{v'\in s_{u},v'\neq v}(f_{v',i-2}+1) vsu,v=v(fv,i2+1)

显然是需要前缀和后缀拼起来的,我们这么考虑:我们让求 f f f 的时候按 d d d 从大到小枚举儿子(这样第一个枚举的一定是重儿子),并记录 f f f 的变化,然后求 g g g 的时候按 d d d 从小到大枚举儿子,前缀显然可以边枚举边求出,而后缀则可以通过不断还原 f f f 求出。

g g g 也可以用 5 个 tag 维护。

有关求逆:我们需要每次 O ( 1 ) O(1) O(1) 计算出 f u , d u f_{u,d_u} fu,du 的逆,注意到此时第二维是没有影响的,所以可以先求出所有的 f u , d u f_{u,d_u} fu,du 再离线 O ( n ) O(n) O(n) 预处理它们的逆元(每个值的逆=全部乘起来的逆×前缀积×后缀积)。

代码没写完。

  • 0
    点赞
  • 0
    评论
  • 1
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 1024 设计师:白松林 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值