笛卡尔树

前言

发现自己居然没有写过笛卡尔树的构建的总结。。

正文

笛卡尔树的概念

待补。

笛卡尔树的构建

我们通过不断维护“最右链”来构造笛卡尔树,也就是每次笛卡尔树的最右链(当前栈)一定是单调递减/增的,然后如果有弹栈操作,我们就把这个节点作为我们当前末尾的左儿子,弹完后这个节点作为当前栈底的右儿子,成为新的最右链的底端。

代码如下:

#include<bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x){
	x=0;bool f=false;char ch=getchar();
	while(!isdigit(ch)){f|=ch=='-',ch=getchar();}
	while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
	x=f?-x:x;
	return ;
}
template <typename T>
inline void write(T x){
	if(x<0) x=-x,putchar('-');
	if(x>9) write(x/10);
	putchar(x%10^48);
	return ;
}
#define ll long long
const int N=1e7+5;
int n,m,a[N],ls[N],rs[N],Root;
ll Ans1,Ans2;
int sta[N],top,siz[N],tmp;
signed main(){
	read(n);
	top=0;
	for(register int i=1;i<=n;i++){
		scanf("%d",&a[i]);tmp=0;
		while(top&&a[sta[top]]>a[i]) tmp=sta[top--];
		rs[sta[top]]=i;ls[i]=tmp;sta[++top]=i;
	}
	for(register int i=1;i<=n;i++) Ans1^=1ll*i*(ls[i]+1),Ans2^=1ll*i*(rs[i]+1);
	write(Ans1),putchar(' '),write(Ans2);
	return 0;
}

笛卡尔树的性质

当前节点是当前区间内的最值,左儿子是左区间的最值,右儿子是右区间的最值。(当然可以改造成多叉的)

笛卡尔树期望构造树高是 \(\log n\) 的。

posted @ 2021-10-27 21:33  __Anchor  阅读(52)  评论(0)    收藏  举报