笛卡尔树

知识来源:https://blog.csdn.net/qq_41551359/article/details/82661138


定义

笛卡尔树是一种特定的二叉树数据结构。它具有堆的有序性,中序遍历可以输出原数列。

图片来自维基百科
图片来自维基百科

 

这张图所展示的是这个数组中每个区间的最小值。

1是9~15这11个数中的最小值

3是9~7这3个数中的最小值

5是8~5这7个数中的最小值,同时也是12~5这6个数中的最小值

8是8~18这6个数中的最小值

以此类推。


应用

一般笛卡尔树都被用来建一颗treap(树堆),复杂度为O(n)的,n表示建树所插入的元素个数。是RMQ(区间最值查询)标准算法的基础。可用来做范围最值查询、范围top k查询、最近公共祖先(LCA)。 


特点

笛卡尔树建树,插入的元素必须保证key值递增(即顺序是不能改变的),而value值是可以乱的。建树的过程中有单调栈的思想。因此很多单调栈能解决的问题,笛卡尔树也能解决。


模版示例

struct Cartesian_Tree{
    
    //创建笛卡尔树的结构
    struct node{
        int index;
        int value;
        int parent;
        int child[2];
        node() {}
        node (int index,int value,int parent): index(index),value(value),parent(parent){
            child[0]=child[1]=0;
        }
    }tree[maxn];
    
    //初始化笛卡尔树,以0作为根,可以直接搜索到整个区间的最小值
    void init(){
        tree[0]=node(0,0,0);
    }
    
    int root,l[maxn],r[maxn];
    
    //创建笛卡尔树
    void build(int n,int *a){
        for(int i=1;i<=n;i++){
            tree[i]=node(i,a[i],0);
        }
        for(int i=1;i<=n;i++){
            int k=i-1;
            //一直找到比i位置小的位置k
            while(tree[k].value>tree[i].value)
                k=tree[k].parent;
            
            //将父节点的右子树放到自己的左子树上,因为不能改变他们映射后的序列位置,因此是将右子树放到左子树
            tree[i].child[0]=tree[k].child[1];
            //父节点的右子树重新指向
            tree[k].child[1]=i;
            //设置i的父节点
            tree[i].parent=k;
            //设置原本为右子树,现改为当前节点的左子树的父亲
            tree[tree[i].child[0]].parent=i;
        }
        //笛卡尔树的根节点设置为根节点的右子树节点(即我们插入的1~n范围里的最值)
        root=tree[0].child[1];
    }
    //通过DFS进行一下判断,该判断是下图的解决方案
    ll ans=0;
    int DFS(int root){
        if(!root) return 0;
        int sz = DFS(tree[root].child[0]);
        sz += DFS(tree[root].child[1]);
        ans = max(ans, (ll)(sz + 1) * tree[root].value);
        return sz + 1;

    }
}tree[2];
HDU-1506(题目集中的1)

 


题目集(做到就会更新):

  1. HDU-1506 Largest Rectangle in a Histogram       ——19.07.19
  2. 牛客暑期多校训练营1—Equivalent Prefixes       ——19.07.19 
  3. 牛客暑期多校训练营2—Second Large Rectangle       ——19.07.20(可以利用1的思想求解)
  4. Leverage MDT       ——19.12.07(HDU1506以行为底找最大矩形,此题以列为底找最大正方形)

欢迎指出不足及错误之处。^_^

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值