笛卡尔树入门

笛卡尔树的定义

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

笛卡尔树的构造

排序令 \(k\) 递增,每次插入一个新的节点,我们要使新插入的元素尽量靠右。
在这里我们假设要插入的点为 \((k_u,w_u)\)

构造步骤:
1、维护一个从根节点开始,每次都向右儿子走的链。这条链可以用栈来维护
2、找到第一个链上的节点 \(x\) 使得 \(w_x\)\(w_u\) 大。
3、i. 若 \(x\) 没有右子树,则将 \(x\) 的右儿子设置为 \(u\)
3、ii. 若 \(x\) 有右子树,则让 \(u\) 替代 \(x\),并将 \(u\) 的左儿子设置为 \(x\)

题目

P5854 【模板】笛卡尔树

模板题

代码示例

P5854代码~

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=10000009;
ll n,p[N];
ll stk[N],top;
ll l[N],r[N];
ll lans,rans;

void input(){
	ios_base::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	cin>>n;
}

void solve(){
	for(ll i=1;i<=n;i++){
		cin>>p[i];
		if(top==0){
			stk[++top]=i;
		}
		else if(p[stk[top]]<p[i]){
			r[stk[top]]=i;
			stk[++top]=i;
		}
		else{
			while(p[stk[top]]>p[i]) top--;
			r[stk[top]]=i;
			l[i]=stk[top+1];
			stk[++top]=i;
		}
	} 
	for(ll i=1;i<=n;i++){
		lans^=i*(l[i]+1);
		rans^=i*(r[i]+1);
	}
	cout<<lans<<" "<<rans;
}

int main(){
	input();
	solve();
	return 0;
}
posted @ 2023-11-05 11:58  lemon-cyy  阅读(28)  评论(0编辑  收藏  举报