定义
一棵树,每个点有两个权值,如果 (a) 权值满足 (BST),(b)权值满足 (heap),那么这棵树 就是一棵笛卡尔树
一般是对于一个序列建笛卡尔树
其实 (Treap) ,就是一个笛卡尔树,不过笛卡尔树不平衡
性质
一棵子树的中序遍历对应原序列中的一个区间
构造
(O(n)) 建树
考虑用单调栈维护最右边的一条链(有点右偏树的意思??)
然后每一次考虑对第二关键字进行单调相关的 (push) , (pop) 操作
如果第二关键字遇到 (RMQ),了就 (break)
随便理解吧
代码:
for(int i=1;i<=n;++i)
{
while(top&&a[st[top]]>a[i]) ls[i]=st[top--];//或者别的RMQ
if(top) rs[st[top]]=i;
st[++top]=i;
}
合并
定义关键点:一个树最左边和最右边两个链
关键点只有初始的(O(n))个
合并 (x,y) 时候,对于 (x) 的右链和 (y) 的左链,从最底下开始往上找到第一个能放的位置,这一段长度设为 (len)
之后这段关键点会被覆盖住,不再存在。
然后 (y) 的这个点左儿子和 (x) 的这个点的右儿子进行类似 (fhq) 的合并,也就是一般的暴力合并
由于路径上的点就是两个段的关键点
关键点然后就消失了。
走的长度就是关键点减少的个数
所以均摊(O(n))
从最底下开始找,可以用链表然后链表合并。单纯记录每个点最右边的点也可以
(size) 什么的(pushup)就找到了。
( (pushup) 这个不太好找到,最开始一段链很难搞。可以用 (LCT) 同时和笛卡尔树合并做,用于打上标记)
直接搬的@(Miracle)的博客……理解力太差,真的没太懂(或者就是不会写)
用途
1.一堆矩形,底贡献,高度不同,求一个最大的子矩形,使得高度和宽度的乘积最大
直接对序列建笛卡尔树,然后对于子树的(size) 和高度求乘积就好
正确性显然(因为 (size) 就是宽度)
这题显然可以考虑单调栈啥的((NOIP2013) 积木大赛)
2.SP3734
我们看到这个是一个直方图,而且形状不规则,就考虑到建一棵笛卡尔树
然后把题目转成在矩形中选点(笛卡尔树把直方图变成一个一个的矩形,然后就是放点了)
这里有个结论:(n imes m) 的矩形中我们放 (k) 点,方案数为:(C^{k}_n imes C^k_m imes k space !)
每个点都占一行和一列,所以两个组合数的乘积就是一个组合,排列数直接乘阶乘就好
然后是笛卡尔树上的 (dp), 这里转移就考虑枚举在每一岔上放几个点就行了,最后加一加,乘一乘