【2020.11.20提高组模拟】祖先(ancestor) 题解

【2020.11.20提高组模拟】祖先(ancestor) 题解

题目描述

对于每个\(i\),它都要往前面拜访它的祖先。对于\(i\)之前的编号为\(j\)的节点,如果要拜访的话需要满足对于\(\forall k\in (j,i],j是k的祖先\)

\(n \le 2*10^6+2*10^5\)

Solution

首先如果用对于每一个\(i\)向前枚举\(j,k\)再判断\(LCA\)或其他暴力等做法的话,时间复杂度\(O(n^4),O(n^3)\)不等。

考虑反过来计算每一个j对其后代的贡献。

首先显然如果有\(i\)将会在\(j\)产生贡献,\(j\)一定是\(i\)的祖先,反过来就是\(i\)\(j\)的子树内,同时\([j,i]\)这段区间都应该在\(j\)的子树内。

如果记录\(dfn\)序之后,我们就可以把这个约束条件写成:

\[\forall i\in[j,n],dfn_j\le dfn_i\le dfn_j+size_j \]

左右拆分,发现可以ST表+二分/倍增得到\(dfn\)的答案区间。

预处理ST表后询问都是\(O(n\log n)\)的。

Code-\(O(n\log n)\)

Std

如何不用把二分变成线性的呢?伟大的\(\texttt{Tommy0103}\)用在跑操时想到了如何像题解一样想出了如何用单调栈维护!

如果\(i\)\(j\)的子树中

\[dfn_j\le dfn_i\le dfn_j+size_j \]

那么\(i\)的子树也当然都在\(j\)的子树内

\[dfn_j\le dfn_i\le dfn_i+size_i\le dfn_j+size_j \]

就可以分成两个单调栈在线性时间复杂度内维护了!

Code

posted @ 2020-11-20 22:18  Vanilla_chan  阅读(240)  评论(0编辑  收藏  举报