前言

笛卡尔树
- 笛卡尔树是一棵二叉树,其有两个值 \((k,w)\),其中 \(k\) 要求满足 \(BST\) 性质,而 \(w\) 要求满足堆性质,不知道 \(BST\) 的可以看我之前的学习笔记
- 我们发现笛卡尔树和 \(Treap\) 非常像,不过 \(Treap\) 是 \(rand\) 一个权值,本质上 \(Treap\) 属于笛卡尔树
- 我们不再按平衡树的方式构建,而是用数组下标作为二元组的键值 \(k\),其中数组下标 \(k\) 满足 \(BST\) 性质
构建
- 笛卡尔树的构建通常采用单调栈,原因是我们上面规定了笛卡尔树以 \(k\) 作为下标,且满足 \(BST\) 性质,所以是单调的
- 构建时就像插入的过程,比如已经有 \(1\) 和 \(7\) 这两个点,要加入 \(3\),就是在 \(1\) 和 \(7\) 中间加入 \(3\),再把 \(7\) 拐为左子树,\(e\),非常复杂,从oiwiki偷张图

- 然后就没了
- 代码随便给了,msjing找了个题解贺的
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
constexpr int maxn=1e7+10;
int read()
{
int x=0,f=1;
char ch=getchar();
while (ch<'0' || ch>'9')
{
if (ch == '-') f=-1;
ch=getchar();
}
while (ch>='0' && ch<='9')
{
x=(x<<1)+(x<<3)+ch-'0';
ch=getchar();
}
return x*f;
}
int n,a[maxn],stk[maxn],top=1,ls[maxn],rs[maxn];
void des()
{
for (int i=2;i<=n;i++)
{
while (a[stk[top]]>a[i] && top) top--;
if (!top) ls[i]=stk[top+1];
else ls[i]=rs[stk[top]],rs[stk[top]]=i;
stk[++top]=i;
}
}
int ans1,ans2;
signed main()
{
n=read();stk[1]=1;
for (int i=1;i<=n;i++) a[i]=read();
des();
for (int i=1;i<=n;i++) ans1^=i*(ls[i]+1),ans2^=i*(rs[i]+1);
printf("%lld %lld\n",ans1,ans2);
return 0;
}
做题
类型
板板
\(solve\)
- 徒手模一下,发现下标满足小根堆,权值满足 \(BST\),符合笛卡尔树,直接按 \(BST\) 为下标搞,由于插入顺序,跑前序遍历,输出就搞完了
sbmqwm:搞完搞完
- msjing:你出去
\(code\)
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
constexpr int maxn=1e5+10;
int read()
{
int x=0,f=1;
char ch=getchar();
while (ch<'0' || ch>'9')
{
if (ch == '-') f=-1;
ch=getchar();
}
while (ch>='0' && ch<='9')
{
x=(x<<1)+(x<<3)+ch-'0';
ch=getchar();
}
return x*f;
}
int n,a[maxn],stk[maxn],top=1,ls[maxn],rs[maxn];
void des()
{
for (int i=2;i<=n;i++)
{
while (a[stk[top]]>a[i] && top) top--;
if (!top) ls[i]=stk[top+1];
else ls[i]=rs[stk[top]],rs[stk[top]]=i;
stk[++top]=i;
}
}
void dfs(int x)
{
if (x == 0) return;
printf("%lld ",x);
dfs(ls[x]);
dfs(rs[x]);
}
signed main()
{
n=read();stk[1]=1;
for (int i=1;i<=n;i++) a[read()]=i;
des();dfs(stk[1]);
return 0;
}
\(dp\)