【算法学习】笛卡尔树

前言

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 @ 2024-10-04 10:06  sad_lin  阅读(8)  评论(0编辑  收藏  举报