笛卡尔树 学习笔记

前置知识

  1. 知道二叉搜索树的定义;
  2. 知道堆的定义,知道小根堆和大根堆的特点与区别。

目录

  • Part 1:笛卡尔树的定义
  • Part 2:笛卡尔树的实现
  • Part 3:推荐练习

Part 1:笛卡尔树的定义

笛卡尔树是一种二叉树,每一个结点由一个键值二元组 (k,w) 构成。要求 k 满足二叉搜索树的性质,而 w 满足堆的性质。一个有趣的事实是,如果笛卡尔树的 k,w 键值确定,且 k 互不相同,w 互不相同,那么这个笛卡尔树的结构是唯一的。(OI Wiki

笛卡尔树是一种非常特殊的二叉搜索树。每个节点有两个信息 (xi,yi),如果只考虑 x,它是一棵二叉搜索树,如果只考虑 y,它是一个小根堆。

Part 2:笛卡尔树的实现

算法简述

在保证 xi 递增的情况下,可以较为轻松地构建一棵笛卡尔树(因为排了序之后,每次插入的新节点都会在这棵树的右链的最后面。所谓右链,即从根节点开始一直向右儿子走,途中经过的节点所组成的链)。

因此,可以用一个单调栈来维护,在出栈的过程中判断,如果当前节点的 x 值严格大于单调栈顶的节点的 x 值,那么就将当前节点作为栈顶节点的右儿子,然后将原本栈顶节点的右子树改为左子树。

代码实现

下面的代码中,ii 节点的 x 值,aii 节点的 y 值。

st 是单调栈,top 表示单调栈的栈顶元素在单调栈中的下标,lsonrson 分别存储了笛卡尔树节点的左右儿子。

 
 
 
 
 
 
inline int build_tree(){
  k=top;
  for(int i=1;i<=n;++i){
    while(k&&a[st[k]]>a[i]) --k;//单调栈
    if(k) rson[st[k]]=i;//如果当前节点的x值严格大于单调栈顶的节点的x值,那么就将当前节点作为栈顶节点的右儿子
    if(k<top) lson[i]=st[k+1];//将原本栈顶节点的右子树改为左子树
    st[++k]=i;//将新结点加入右链
    top=k;
  }
  return st[1];//返回根节点
}
 

Part 3:推荐练习

posted @ 2022-02-19 11:05  xiaomuyun  阅读(68)  评论(0编辑  收藏  举报