[学习笔记]笛卡尔树
笛卡尔树是一种二叉树,每一个结点由一个键值二元组
比如这就是一棵以下标为
在保证
每次插入一个新节点时,为了确保二叉搜索树的性质得到满足(别忘了我们按照 xxx 递增的顺序插入),我们需要将新节点一个一个插入到当前的笛卡尔树中
那么每次我们插入的元素必然在这个树的右链(右链:即从根结点一直往右子树走,经过的结点形成的链)的末端
更具体地来说,我们设当前要插入的点为
然后将
维护这样一条链可以用栈实现。因为每个节点最多进栈出栈各一次,总时间复杂度是
下面是建树过程
建树可以用单调栈维护一个权值单调递增的下标序列,从栈顶向底部遍历
插入一个点时作为右儿子插入到第一个比它小的点(如果有的话)后,如果遇到了比它大的点,将最后一个比它大的点作为左儿子
for(int i=1;i<=n;i++){
a[i]=read();
pos=top;
while(pos&&a[stk[pos]]>a[i]) pos--;
if(pos) tree[stk[pos]].r=i;
if(pos<top) tree[i].l=stk[pos+1];
stk[++pos]=i;
top=pos;
}
还是看一道模板题:
注意到只要单纯地建树即可
点击查看代码
#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<vector>
#include<deque>
#include<stack>
#define int long long
#define WR WinterRain
using namespace std;
const int WR=10001000,mod=1e9+7,INF=1099511627776;
struct Cartesian_Tree{
int l,r;
}tree[WR];
int n;
int stk[WR],top,pos;
int a[WR];
int read(){
int s=0,w=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-') w=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
s=(s<<1)+(s<<3)+ch-'0';
ch=getchar();
}
return s*w;
}
signed main(){
n=read();
for(int i=1;i<=n;i++){
a[i]=read();
pos=top;
while(pos&&a[stk[pos]]>a[i]) pos--;
if(pos) tree[stk[pos]].r=i;
if(pos<top) tree[i].l=stk[pos+1];
stk[++pos]=i;
top=pos;
}
int L=0,R=0;
for(int i=1;i<=n;i++){
L^=i*(tree[i].l+1);
R^=i*(tree[i].r+1);
}
printf("%lld %lld\n",L,R);
return 0;
}
那么考虑另外一道题目:
也是一道比较板子的题目
那么为什么要建笛卡尔树呢?
因为给定的序列一定是
一个元素越在序列后边,它在二叉搜索树中的位置越深,换句话说,对于一个数
所以可以把第几个插入看做权值
点击查看代码
#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<vector>
#include<deque>
#include<stack>
#define int long long
#define WR WinterRain
using namespace std;
const int WR=10001000,mod=1e9+7,INF=1099511627776;
struct Cartesian_Tree{
int l,r;
}tree[WR];
int n;
int stk[WR],top,pos;
int a[WR];
int read(){
int s=0,w=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-') w=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
s=(s<<1)+(s<<3)+ch-'0';
ch=getchar();
}
return s*w;
}
void prior(int x){
printf("%lld ",x);
if(tree[x].l) prior(tree[x].l);
if(tree[x].r) prior(tree[x].r);
}
signed main(){
n=read();
for(int i=1;i<=n;i++){
int x=read();
a[x]=i;
}
for(int i=1;i<=n;i++){
pos=top;
while(pos&&a[stk[pos]]>a[i]) pos--;
if(pos) tree[stk[pos]].r=i;
if(pos<top) tree[i].l=stk[pos+1];
stk[++pos]=i;
top=pos;
}
prior(stk[1]);
printf("\n");
return 0;
}
差不多就是这些了QWQ
本文来自博客园,作者:冬天的雨WR,转载请注明原文链接:https://www.cnblogs.com/WintersRain/p/16736649.html
为了一切不改变的理想,为了改变不理想的一切
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】