考虑这样一类问题:有一个序列
a1…n,每次询问一个区间建出来的笛卡尔树上的一些事情。
不妨假设
ai 互不相同,我们需要的是大根笛卡尔树。考虑怎么刻画一个区间
[l,r] 的笛卡尔树:
- 首先根是区间最大值:p0=argi∈[l,r]maxai。
- 考虑根的左子树 [l,p0),有左子树的根 p1=argi∈[l,p0)maxai。
- 我们可以发现 p1 的右子树就是 p1 在整个序列的笛卡尔树上的右子树;p1 的左子树 p2=argi∈[l,p1)maxai,以此类推直到 pk=l。
- 容易发现 pk,pk−1,…,p0 就是这个区间的所有前缀最大值的位置;根的左儿子就是这些前缀最大值(不包括 p0)和它们在整个序列的笛卡尔树上的右儿子拼起来的结果。
- 维护的方式因题而异,一种常见的做法是从右到左扫描线,用一个递减的单调栈维护 [l,n] 的前缀最大值;p1,…,pk 就是单调栈的一个后缀,在单调栈上维护需要维护的信息。根的右儿子就是全部反过来,在最后拼出来根的信息。
QOJ14417. Roman Numerals
题意:有序列
ai,bi,对区间
ai 建出笛卡尔树,点
u 有
fu=bu−flsu+frsu,求根的答案。
首先我们对整个序列建出笛卡尔树并处理出
fu。先考虑右儿子怎么做,可以发现就是单调栈上的一个后缀
bu−flsu 加起来,做一个前缀和就行。
左儿子也是类似,但是每个点的贡献要乘上
(−1)depu。我们先将在单调栈上的位置的奇偶性当作深度的奇偶性,询问的时候分讨一下
p0 位置的奇偶性。
通常为了方便,第一步的区间 RMQ 可以直接在单调栈上二分。本题使用线性 RMQ 即可做到线性,但通常没有什么必要。
P5044 [IOI 2018] 会议
题意:有序列
ai,每次询问
i∈[l,r]minj∈[l,r]∑k∈[min(i,j),max(i,j)]maxak。
我们先在笛卡尔树上写出 DP:
fu=min(flsu+au(szrsu+1),frsu+au(szlsu+1))。
两边是对称的,我们就只考虑左边。我们考虑最小的
i 使得
pi 采用了第二种转移,即
fpi=frs+api(pi−l+1),那
fp1=fpi+1≤j<i∑apj(szrspj+1),答案就是所有
pi 的结果的最小值。在单调栈上前缀和然后拆贡献,KTT 维护一次函数最值。
O(nlog2n)。
P13540 [IOI 2025] 羊驼的坎坷之旅
题意:有一个网格,一个单元格
(x,y) 合法当且仅当
ax>by,问保留第
[l,r] 列,
(0,x) 能不能走到
(0,y)。
我们猜测路径一定形如一堆
(0,a)→(x,a)→(x,b)→(0,b)。设一列中第一个空的位置是
fii,前缀连续空的长度是
cni,
a→b 之间的
maxb 位置为
c,那能这么走就相当于
fic≤min(cna,cnb)。
我们建出
b 的笛卡尔树。对于一个子树
x,如果我们能到达
fix 且子树
maxcn≥fifax 就可以走到
fifax,询问的时候只要看能跳到最高的位置是否相等。
考虑区间笛卡尔树,所有前缀
max 相当于不停跳到右侧第一个
>bi 的位置,这个也能建出一棵树,在全局的笛卡尔树上倍增到子树不被
[l+1,r−1] 包含后变成在这棵树上倍增即可。
O(nlogn)。