Description
给出了一棵以1为根的有n个节点的树。
m组询问,每个询问选择一个区间[l,r]。
你需要回答满足 z ∈ [ 1 , n ] z\in [1,n] z∈[1,n]且存在 x , y ∈ [ l , r ] x,y\in[l,r] x,y∈[l,r]使得 l c a ( x , y ) = z lca(x,y)=z lca(x,y)=z的 z z z的个数。
n , m ≤ 3 × 1 0 5 n,m\leq 3\times10^5 n,m≤3×105
Solution
好题啊
考虑对于一个点,表示出能贡献的区间
对于两个点 x , y , x < y x,y,x<y x,y,x<y,令 z = l c a ( x , y ) z=lca(x,y) z=lca(x,y),那么至少对于所有的 [ l , r ] , l ≤ x , y ≤ r [l,r],l\leq x,y\leq r [l,r],l≤x,y≤r,z都是可以贡献的。
先将z本身就在区间 [ l , r ] [l,r] [l,r]中的情况排除
我们可以设法找出所有点对x,y,当然这是不现实的,我们可以考虑只找出极小的点对,即x与y最接近的那些。
这样思路就明朗了,对于每一个z,枚举它子树中的节点p,令它作为上面的y,也就是说只需要找到z的除p所在的子树的其他子树中最大的 q q q满足 q < p q<p q<p,这样就求出了一对点对。
我们发现这样效率很低
考虑启发式合并,即子树大小最大的那个儿子(即轻重链剖分的重儿子)中我们不枚举,只枚举轻儿子,此时不仅要求最大的
q
q
q满足
q
<
p
q<p
q<p,还要求最小的
q
′
q'
q′满足
q
′
>
p
q'>p
q′>p,这个用个set维护一下就好了,合并就启发式暴力合并。
这样我们算出来的点对只有
O
(
n
log
n
)
O(n\log n)
O(nlogn)对
考虑计算答案。
扫描线,从小到大枚举询问区间右端点,设
l
e
f
t
[
i
]
left[i]
left[i]表示节点i此时能贡献所有
l
≤
l
e
f
t
[
i
]
l\leq left[i]
l≤left[i]的询问,显然它是单调不降的。
我们将点对挂在相应的y处,枚举到就直接改left就行了,询问就用树状数组查询。
总的时间复杂度 O ( n log 2 n ) O(n\log ^2 n) O(nlog2n)