笛卡尔树(Cartesian Tree)

笛卡尔树(Cartesian Tree)

1. 定义

根据序列构造的满足以下性质的树:

  • 二叉搜索树性质(BST):keylskeyxkeyrskey 默认为下标。
  • 堆性质:valxvallsvalrs.

2. 构造

  • 如果有 key 作为第一关键字,则按 key 升序排序,否则默认下标为 key
  • 使用单调栈维护右链,按照 key 升序的顺序添加节点。
  • 加入一个新节点 i 时,找到右链上第一个 valjvali 的节点,将 rsj 作为 i 的左儿子,i 作为新的 rsj.
const int N = 1e5 + 5;
int n, root, v[N], fa[N], ls[N], rs[N];
stack<int> stk;

void build()
{
	for(int i = 1; i <= n; i++)
	{
		cin >> v[i];
		while(!stk.empty() && v[stk.top()] > v[i])
			ls[i] = stk.top(), stk.pop();
		fa[i] = (!stk.empty() ? stk.top() : 0);
		if(!fa[i]) root = i;
		if(ls[i]) fa[ls[i]] = i;
		if(fa[i]) rs[fa[i]] = i;
		stk.push(i);
	}
	return;
}

3. 应用

3.1. 求区间最小值(RMQ)

建立小根笛卡尔树,区间 [a,b] 的最小值是 valLCA(a,b).

利用 BST 的性质可以快速求 LCA.

复杂度为树的深度,随机数据下为 O(nlogn).

int find_min(int a, int b)
{
	int lca = root;
	while(lca < a || lca > b)
	{
		if(lca < a) lca = rs[lca];
		if(lca > b) lca = ls[lca];
	}
	return v[lca];
}

3.2. 求最小值范围

给定一个无序序列和一个下标,求对应的值是多大范围内的最小值。

  • 建立小根笛卡尔树,下标 i 对应的区间为 i 的子树中最左边的点到最右边的点。

3.3. 最大矩形

求下图的最大矩形(n105):

image

  • 建立小根笛卡尔树,每个点的贡献是 子树大小×深度.

4. 例题

4.1. P1350 车的放置

fi,j:在 i 的子树中放 j 个车的方案数。

fu,i=ij=0soni×j!(i1j)(w(ij)j).

soni=ij=0(flc,j×frc,ij).

n×m 的矩形中放 k 个车:Ckn×Ckm×k!.

posted @   心灵震荡  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示