笛卡尔树 学习笔记

定义

笛卡尔树是一种树,每个节点有两个权值 \(\left(x_i,y_i\right)\)。如果单看 \(x_i\),它是一棵二叉搜索树(BST);如果单看 \(y_i\),它是个小根堆(Heap)。
其实 Treap 就是一种笛卡尔树,只不过 \(y_i\) 是随机赋值的。

构建

板子题
首先按照 \((x_i)\) 升序排序(这题不需要)。
接下来就是一个一个插入了。我们发现要插入的点全部在右链(即从根结点一直往右子树走,经过的结点形成的链)上,所以我们需要维护右链上的节点。
我们发现右链上的点最多进出一次(或者说每个点在右链中存在的是一段连续的时间),所以我们就可以用栈维护右链上的节点,复杂度为 \(\Theta\left(n\right)\)

代码如下:

#include<cstdio>
#define maxn 10000039
using namespace std;
int n,p[maxn];
struct JTZ{ int ls,rs; }a[maxn];
int s[maxn],top,k; ll ansl,ansr;
int main(){
	scanf("%d",&n); register int i; top=0; for(i=1;i<=n;i++) scanf("%d",&p[i]);
	for(i=1;i<=n;i++){
		k=top; while(top&&p[s[k]]>p[i]) k--;
		if(k) a[s[k]].rs=i;
		if(k<top) a[i].ls=s[k+1];
		s[++k]=i; top=k;
	} ansl=ansr=0;
	for(i=1;i<=n;i++) ansl^=1ll*i*(a[i].ls+1),ansr^=1ll*i*(a[i].rs+1);
	printf("%lld %lld",ansl,ansr);
	return 0;
}
posted @ 2021-10-10 20:42  jiangtaizhe001  阅读(36)  评论(0编辑  收藏  举报