知识来源:https://blog.youkuaiyun.com/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 Largest Rectangle in a Histogram ——19.07.19
- 牛客暑期多校训练营1—Equivalent Prefixes ——19.07.19
- 牛客暑期多校训练营2—Second Large Rectangle ——19.07.20(可以利用1的思想求解)
- Leverage MDT ——19.12.07(HDU1506以行为底找最大矩形,此题以列为底找最大正方形)
欢迎指出不足及错误之处。^_^