定义

笛卡尔树一是一棵二叉树。对于每个结点,有两个权值 k,wk,w。 若只看 kk,整颗树为二叉查找树;只看 ww,树为堆。

如图,点在数组中的位置号码为 kk,元素内数字为 ww

性质

  • 若每个 k,wk,w 均不相同,则笛卡尔树的形式是唯一的。

  • 结点要么没有左儿子,要么左儿子没有左儿子。

建树

这里默认堆为小根堆。

用单调栈维护树的右链。

设新加入点 uu,若栈中(即右链)所有 ww 值均大于 wuw_u,则栈底(即右链头即当前树根)变为 uu 左儿子。

若栈中第一个 ww 小于 uu 的点为 vv,则 vv 的右儿子全部变为 uu 的左儿子,uu 成为 vv 的右儿子。

code

模板题 [P5854] 笛卡尔树

#include <bits/stdc++.h>
#define rei register int
#define N 10000010
using namespace std;
typedef long long ll;

template <typename T> inline void read(T &x)
{
	x = 0; int f = 1; char ch = getchar();
	while (!isdigit(ch)) {if (ch == '-') f = -f; ch = getchar();}
	while (isdigit(ch)) {x = x * 10 + ch - 48; ch = getchar();}
	x *= f;
}

int n, a[N], st[N], top, ls[N], rs[N];
ll ansl, ansr;

int main()
{
	read(n);
	for (rei i = 1; i <= n; i++) read(a[i]);
	for (rei i = 1; i <= n; i++)
	{
		while (top && a[st[top]] > a[i]) top--;
		if (!top) ls[i] = st[top + 1];
		else ls[i] = rs[st[top]], rs[st[top]] = i;
		st[++top] = i;
	}
	for (rei i = 1; i <= n; i++) ansl ^= (1ll * i * (ls[i] + 1)), ansr ^= (1ll * i * (rs[i] + 1));
	printf("%lld %lld", ansl, ansr);
	return 0;
}

例题1

P1377 [TJOI2011]树的序

此题与模板不同在于,位置号码为 ww 值,元素内数字为 kk 值。

则需对原数组排序,再按排序后顺序建树。

kk 值字典序最小,根据二叉查找树性质,答案为先序遍历结果。

顺便得出结论:谁有二叉查找树性质,就要按其顺序建树。

#include <bits/stdc++.h>
#define rei register int
#define N 100010
using namespace std;

template <typename T> inline void read(T &x)
{
	x = 0; int f = 1; char ch = getchar();
	while (!isdigit(ch)) {if (ch == '-') f = -f; ch = getchar();}
	while (isdigit(ch)) {x = x * 10 + ch - 48; ch = getchar();}
	x *= f;
}

int n, st[N], top, x, ls[N], rs[N];
struct Node {int k, w;} a[N];

inline void Dfs(int u)
{
	printf("%d ", u);
	if (ls[u]) Dfs(ls[u]);
	if (rs[u]) Dfs(rs[u]);
}

inline bool cmp(const Node &a, const Node &b) {return a.k < b.k;}

int main()
{
	read(n);
	for (rei i = 1; i <= n; i++) read(a[i].k), a[i].w = i;
	sort(a + 1, a + 1 + n, cmp);
	for (rei i = 1; i <= n; i++)
	{
		while (top && a[st[top]].w > a[i].w) top--;
		if (!top) ls[i] = st[top + 1];
		else ls[i] = rs[st[top]], rs[st[top]] = i;
		st[++top] = i;
	}
	Dfs(st[1]);
	return 0;
}