笛卡尔树 学习笔记
定义
笛卡尔树是一种树,每个节点有两个权值 \(\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;
}