笛卡尔树

笛卡尔树是一种二叉树,每个节点有两个键值 \(x,y\) ,一个满足BST,一个满足堆。上图:

一个性质是如果键值确定那么笛卡尔树是唯一的。

笛卡尔树如果暴力构造很简单:找到整个序列最大/小的一个元素,将它作为当前的根节点,然后左右两边向下递归。但是这并不优秀。事实上我们有 \(O(n)\) 的构建方法。

我们按照下标(满足BST性质的一维)递增顺序将每个元素插入笛卡尔树,同时用一个栈维护一条最右链。那么我们每次插入的元素一定在这条链的末端。再来图:

假设我们当前插入 \(a\) ,那么我们找到链上第一个 \(y\)\(y_a\) 更大/小的节点,把它的右儿子设置为 \(a\) ,然后把它原来的右子树改成 \(x\) 的左子树(之前插入的都比 \(x\) 小所以接到左边)。

void build(){
    for(int i=1;i<=n;i++){
        a[i]=read();
        int ret=top;
        while(ret&&a[stk[ret]]>a[i])ret--;
        //在最右链中找第一个权值更小的节点(小根堆)
        if(ret)rson[stk[ret]]=i;
        //改成右儿子
        if(ret<top)lson[i]=s[ret+1];
        //把左儿子接过来
        s[++ret]=i;top=ret;//入栈
    }
}

然后是它的一个小性质:对一个序列建树之后区间 \([l,r]\) 的最大/小值就是笛卡尔树上节点 \(l,r\) 对应点的LCA。可以拿来搞 \(\pm1 \text{RMQ}\) ,还有个东西叫四毛子,以后再说。

别的似乎没什么大用处。

对了还有之前一个考试题,超级加倍 T3

posted @ 2022-09-27 20:24  gtm1514  阅读(74)  评论(0编辑  收藏  举报