【算法学习】笛卡尔树

前言

oi-wiki 已讲的足够清晰

顺着思路看下去还是很简单的,我只列出代码展示。

我现在肯定不会这么说了,虽然考这个的概率还是很小但还是要记录的(学习是给自己学的,笔记是给自己记的)

笛卡尔树要满足堆和二叉搜索树的两个性质,而且他有两种键值 \(w,k\),分别是根节点大于子节点,左节点小于根节点,根节点小于右节点。

竞赛中使用笛卡尔树时,常用数组下标作为二元组的键值 \(k\)

真的讲解

我们将使用栈构建树,我们始终维护一条右链,当插入一个点,在链上找到第一个w小于该节点的节点,将该节点的右子树接在新点的左子树上,新点成为新右链的最后一个点,过程正如 oi-wiki 一样。

图片

然后上代码,感觉比 wiki 还简单明显。
s[1]=1;
int top=1;
for(int i=2;i<=n;i++){
while(a[s[top]]>a[i]&&top){
top--;
}
if(!top){
l[i]=s[top+1];
}
else{
l[i]=r[s[top]];
r[s[top]]=i;
}
s[++top]=i;
}

题目练习

P5854 【模板】笛卡尔树

就是一个板子,按上面说的写就可以,我就不出代码你能怎样,自己写!!!

P1377 [TJOI2011] 树的序

这题需要读懂题意才可以,发现就是个构造笛卡尔树的题,但是好像又不是模板题,怎么办,我们将序列排序使得字典序最小,然后我们按照位置id加点使得不破坏树的插入顺序,每次加入点和笛卡尔树一样放左接右,因为我们是按id加点,所以应该早加的终究会在上方,只不过在过程中使得能在上方加在左子树的尽量在上。

image

image

点击查看代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+10;
#define int ll
int n;
int l[N];
int r[N];
int s[N];
struct ss{
int a,id;
}a[N];
void dfs(int x){
if(x==0){
return;
}
cout<<a[x].a<<" ";
dfs(l[x]);
dfs(r[x]);
}
bool cmp(ss g,ss h){
return g.a<h.a;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i].a;
a[i].id=i;
}
sort(a+1,a+n+1,cmp);
int top=0;
for(int i=1;i<=n;i++){
while(a[s[top]].id>a[i].id&&top){
top--;
}
l[i]=r[s[top]];
r[s[top]]=i;
s[++top]=i;
}
dfs(r[0]);
return 0;
}
posted @   sad_lin  阅读(16)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示