笛卡尔树:在范围最值查询、范围top k查询等问题上有广泛应用。它具有堆的有序性,中序遍历可以输出原数列。
一、定义与性质
首先先明确,笛卡尔树的构建是根据两个键值来的,第一个是他的if顺序,另一个是他维护的权值(最大或者最小),满足每个节点的根都是两边区间的最小值(性质),比如说 序列 :3 1 5 4 2 它的笛卡尔树就是这样的:
首先,可以看出它满足 id从左到右的顺序,其次每个根都是两边区间最小值。
二、建树
笛卡尔树的建立与单调栈有关,因为这个树要满足id从左到右建立,所以新来的元素 只有两种情况 1.成为 父亲节点(在右) 2.成为儿子节点(在右),但建立过程中会出现 3 1 5 4 2 的情况 5 比1 小 所以 5 成为1 的右儿子,但4又来了,4比5小所以4应该成为5的右父亲,就这么一个过程。具体操作用单调栈还实现:
void get_tree()
{
int s=0;
for(int i=1;i<=n;i++)
{
while(s&&num[i]<=num[st[s]])
l[i]=st[s--];//难
if(st[s]) r[st[s]]=i;//难
st[++s]=i;
}
}
用个最简单的例子 来解释 最难理解的那一部分:2 3 4 5 1 和 1 3 4 5 2
2 3 4 5 1:在1到来之前 的链是这样的 3是2的右儿子,4是3的右儿子,5是4的右儿子:
1来了之后 1尝试着去***去(因为1比之前的小 ,1插入的位置可以确定 哪个区间的最小值)
1在尝试他能插到哪个地方结果插到了顶部,那么这个树的定点就会成为1的左二子,连过去就可以了。
同样地:1 3 4 5 2 刚开始 1 3 4 5 是一条链
最后到1 停了,说明2是1的右儿子,所以1的右儿子指向了2,因为3 4 5 在2左边,所以2的左二子是3,所以该图构建结束。
其实过程就是单调栈的过程所以用单调栈维护建树就可以了。
总结:
笛卡尔树在处理区间的topk问题上还是挺好用的,而且每一个最小值维护的区间可以轻松的看出。方便解决问题