【题目】湖南集训 谈笑风生

题目大意

给出一棵 n n n个节点的有根树,其中 1 1 1为根结点。有 q q q个询问,询问给定两个整数 p p p k k k,问有多少个有序三元组 ( a , b , c ) (a,b,c) (a,b,c)满足:

  1. a , b , c a,b,c a,b,c为树上三个不同的点,且 a a a p p p号节点。
  2. a , b a,b a,b都是 c c c的祖先。
  3. a , b a,b a,b在树上的距离不超过 k k k

n ⩽ 300000 n\leqslant 300000 n300000 q ⩽ 300000 q\leqslant 300000 q300000


思路

容易发现 a a a的值是确定的(就是 p p p)。
定义以点 x x x为根的子树大小为 s i z e [ x ] size[x] size[x],点 x x x的深度为 d e p [ x ] dep[x] dep[x]。然后下面就有两种思路:

思路1:
假定 a , b a,b a,b不变,考虑 c c c可能的位置。有下面两种情况:

  • b b b a a a的上方,那么 c c c一定在 a a a的下方,即在以 a a a为根的子树内。此时 c c c对答案的贡献为 s i z e [ a ] − 1 size[a]-1 size[a]1。而 b b b只能在 a a a到根节点的这条链上,可能的位置数为 min ⁡ { d e p [ a ] − 1 , k } \min\{dep[a]-1,k\} min{dep[a]1,k}
  • b b b a a a的下方,那么 c c c一定在 b b b的下方,同理,此时 c c c对答案的贡献为 s i z e [ b ] − 1 size[b]-1 size[b]1。而 b b b需满足 0 < d e p [ b ] − d e p [ a ] ⩽ k 0<dep[b]-dep[a]\leqslant k 0<dep[b]dep[a]k,保证 b b b a a a的下方且距离不超过 k k k

所以对于每一个可能的 b b b,所有的 c c c的贡献之和(因为 a a a是确定的,所以这就是最终答案)为

a n s = min ⁡ { d e p [ a ] − 1 , k } ⋅ ( s i z e [ a ] − 1 ) + ( ∑ d e p [ b ] − d e p [ a ] ∈ ( 0 , k ] ( s i z e [ b ] − 1 ) ) = min ⁡ { d e p [ a ] − 1 , k } ⋅ ( s i z e [ a ] − 1 ) + ( ∑ d e p [ x ] > d e p [ a ] ( s i z e [ x ] − 1 ) ) − ( ∑ d e p [ y ] > d e p [ a ] + k ( s i z e [ y ] − 1 ) ) \begin{aligned} ans&=\min\{dep[a]-1,k\}\cdot(size[a]-1)+\bigg(\sum_{dep[b]-dep[a]\in(0,k]}\bigg(size[b]-1\bigg)\bigg)\\ &=\min\{dep[a]-1,k\}\cdot(size[a]-1)+\bigg(\sum_{dep[x]>dep[a]}\bigg(size[x]-1\bigg)\bigg)-\bigg(\sum_{dep[y]>dep[a]+k}\bigg(size[y]-1\bigg)\bigg) \end{aligned} ans=min{dep[a]1,k}(size[a]1)+(dep[b]dep[a](0,k](size[b]1))=min{dep[a]1,k}(size[a]1)+(dep[x]>dep[a](size[x]1))(dep[y]>dep[a]+k(size[y]1))

其中 b , x , y b,x,y b,x,y都在以 a a a为根的子树内。
对于等式变换的解释: b b b是在 a a a的下方且距离不超过 k k k的点,这些点可以通过容斥得到,用 a a a下方所有的结点 x x x减去距离超过 k k k的结点 y y y

思路2:
假定 a , c a,c a,c不变,考虑 b b b可能的位置。
由于 a a a c c c的祖先, c c c一定在以 a a a为根的子树内,然后 b b b就一定在从 c c c到根节点的这条链上。这条链被点 a a a分成了两段, b b b在这两段链上能放的位置数分别为 min ⁡ { d e p [ c ] − d e p [ a ] − 1 , k } \min\{dep[c]-dep[a]-1,k\} min{dep[c]dep[a]1,k} min ⁡ { d e p [ a ] − 1 , k } \min\{dep[a]-1,k\} min{dep[a]1,k}

对于所有 a a a下面的 c c c,所有的 b b b的贡献之和为
a n s = ∑ c ( min ⁡ { d e p [ c ] − d e p [ a ] − 1 , k } + min ⁡ { d e p [ a ] − 1 , k } ) = ( ∑ c min ⁡ { d e p [ c ] − d e p [ a ] − 1 , k } ) + ( s i z e [ a ] − 1 ) ⋅ min ⁡ { d e p [ a ] − 1 , k } = ( ∑ d e p [ c ] ⩽ d e p [ a ] + k + 1 ( d e p [ c ] − d e p [ a ] − 1 ) ) + ( ∑ d e p [ c ] > d e p [ a ] + k + 1 k ) + ( s i z e [ a ] − 1 ) ⋅ min ⁡ { d e p [ a ] − 1 , k } \begin{aligned} ans&=\sum_c\bigg(\min\{dep[c]-dep[a]-1,k\}+\min\{dep[a]-1,k\}\bigg)\\ &=\bigg(\sum_c\min\{dep[c]-dep[a]-1,k\}\bigg)+(size[a]-1)\cdot\min\{dep[a]-1,k\}\\ &=\bigg(\sum_{dep[c]\leqslant dep[a]+k+1}\bigg(dep[c]-dep[a]-1\bigg)\bigg)+\bigg(\sum_{dep[c]>dep[a]+k+1}k\bigg)+(size[a]-1)\cdot\min\{dep[a]-1,k\} \end{aligned} ans=c(min{dep[c]dep[a]1,k}+min{dep[a]1,k})=(cmin{dep[c]dep[a]1,k})+(size[a]1)min{dep[a]1,k}=(dep[c]dep[a]+k+1(dep[c]dep[a]1))+(dep[c]>dep[a]+k+1k)+(size[a]1)min{dep[a]1,k}

问题来了,怎么求这个 a n s ans ans
两个式子里都有 min ⁡ { d e p [ a ] − 1 , k } ⋅ ( s i z e [ a ] − 1 ) \min\{dep[a]-1,k\}\cdot(size[a]-1) min{dep[a]1,k}(size[a]1),这一部分是可以直接根据给定的 p , k p,k p,k算出来的,可以不管。
式子里另外一堆 ∑ \sum ,本人研究了两种做法:分块、离线+树状数组。实测树状数组跑得飞快;分块做法在洛谷上吸氧能过,但在NKOJ始终有一个点被卡。
主席树、长链剖分什么的不在NOIP (早就没了) 的考纲内,这里不谈。

对于思路1:

分块做法: 由于 b b b a a a的子树内,先将所有结点按照dfs序放入一个数组中,结点 x x x记录 d e p [ x ] dep[x] dep[x] s i z e [ x ] − 1 size[x]-1 size[x]1。对于每一个块,另外维护一个按 d e p dep dep值排序的结点序列以及这个序列的 s i z e [ x ] − 1 size[x]-1 size[x]1值的前缀和。问题就变成了在 a a a的子树所覆盖的区间内(除了 a a a本身)找出 d e p [ x ] dep[x] dep[x]大于某个常数的结点的 s i z e [ x ] − 1 size[x]-1 size[x]1之和。区间两边直接暴力统计,区间中间可以在有序序列中二分查找第一个 d e p [ x ] dep[x] dep[x]大于该数的位置,用前缀和统计答案。

树状数组做法: 看到上面的“找出 d e p [ x ] dep[x] dep[x]大于某个常数的结点的 s i z e [ x ] − 1 size[x]-1 size[x]1之和”,容易想到以 d e p [ x ] dep[x] dep[x]为下标,以 s i z e [ x ] − 1 size[x]-1 size[x]1的和为值,建立树状数组。但是这样不能保证查询的 x x x都在 a a a的子树内 (主席树偷笑)
这里用到了某一道神题中的差分思想:将询问离线,在dfs的过程中统计每个结点的答案。当进入某个结点时,树状数组的每个位置有一个值;当离开这个结点时,树状数组的每个位置又有一个新值;这两个值之差就是以该结点为根的子树产生的贡献。

对于思路2:

分块做法: 同样按照dfs序询问区间,不过每个结点只需要记录 d e p dep dep值。同样二分查找第一个大于 d e p [ a ] + k + 1 dep[a]+k+1 dep[a]+k+1的位置,统计 d e p [ x ] dep[x] dep[x]的前缀和;不同的是还要统计这样的点 x x x的个数,这样才能知道应该减去多少个 d e p [ a ] + 1 dep[a]+1 dep[a]+1,加上多少个 k k k

树状数组做法: 略。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值