zoukankan      html  css  js  c++  java
  • [模板] 笛卡尔树 && RMQ

    话说我noip之前为什么要学这种东西...

    简介

    笛卡尔树(Cartesian Tree) 是一种二叉树, 且同时具有以下两种性质:

    1. 父亲节点的值大于/小于子节点的值;
    2. 中序遍历的结果为原序列.

    笛卡尔树可以实现 (O(n)) 预处理, 均摊 (O(1)) 查询的序列rmq操作.

    建立

    由于第2条性质, 插入的新节点一定在二叉树的右子树链上.

    维护一个右子树链的栈, 进行以下操作:

    1. 插入一个新节点 (p)
    2. 如果栈顶元素 (u) 的值小于 (p), 弹出 (u), 并将其设为 (p) 的左儿子
      否则, (p)(u) 的右儿子.
    3. 最后, 栈顶元素即为树的根.

    代码:

    //a[] : the sequence
    struct tnd{int ch[2];}car[nsz];
    int rt,pc=0;
    int stk[nsz],top=0;
    void build(){
    	rep(i,1,n){
    		while(top&&a[stk[top]]<a[i])car[i].ch[0]=stk[top--];
    		car[stk[top]].ch[1]=i;
    		stk[++top]=i;
    	}
    	rt=stk[1],pc=n;
    }
    

    应用

    序列RMQ

    显然, 建好笛卡尔树后, 两个节点 (p)(q)(lca) 即为以这两点为端点的区间的最大/最小值.

    我们可以 (O(log n)) 单次求lca, 或者用 tarjan 均摊 (O(1)) 求 lca. 虽然比 log 快但是常数巨大

    当数据随机时, 树高期望 (log n), 因此可以从树顶直接向下找儿子来求RMQ. 常数巨小, 比zkw线段树直接RMQ还小.

    跑的比tarjan不知道快到哪里去了

    扔一道题
    11/1/2018模拟 Max

  • 相关阅读:
    C struct的内存对齐
    C++ 继承、函数重载
    C++ 操作符重载
    C中入栈顺序和运算顺序有关系吗?
    Java 关于finally、static
    C++ 类的复制控制
    Linux中vi的使用
    C++ 类的头文件、实现、使用
    (web)个人项目(挖宝网)
    MariaDB使用enum和set
  • 原文地址:https://www.cnblogs.com/ubospica/p/9889315.html
Copyright © 2011-2022 走看看