首页 > 其他分享 >笛卡尔树

笛卡尔树

时间:2022-10-07 19:22:42浏览次数:46  
标签:index 下标 笛卡尔 int Top 节点

在我的心里 NOI 大纲内提高级最难的知识点是圆方树、平衡树和笛卡尔树,平衡树自从自学了 DHQ-treap 后倒是有所改观,今天又重学笛卡尔树,发现貌似并不是那么难(原理上)。看来是我第一次听的时候重视代码而忽略原理了……

笛卡尔树可以定义为:一棵每个节点有 2 个值的二叉树,第一个值为 index(下标),第二个值为 value(数值),而这棵树满足以下限制:

  • value 满足堆性质,即要不然一个节点比其 2 个儿子的 value 值都大(大根堆)要不然比其 2 个儿子的 value 值都小(小根堆)。

  • index 满足二叉搜索树性质,即左儿子的 index 比此节点的 index 小,右儿子的 index 比此节点的 index 大。

先假设我根据给出的一个数组,已经建好了这样一棵树,它能拿来干什么呢?

对于下标为 i 的数,设其左边第一个比它大的数为 \(l_i\),右边第一个比它大的数为 \(r_i\),则建立小根堆笛卡尔树,在树上找到这个下标,则 \(l_i\) 为这个下标的左儿子的子树内的最大下标,即先往左走再一直往右走直到没得走,所到达的那个节点的下标。\(r_i\) 同理可得。

我依稀记得有一个特殊性质,就是每个节点的左右子树 Size 较小的一方之和的量级为 \(O(n\log n)\)。我暂时不会证明,以后来补。

如何实现:按照下标,从 \(1\) 到 \(n\) 往笛卡尔树中加入节点。这里默认是建立小根堆笛卡尔树(大根堆只需要变一个符号,大同小异)。

因为下标递增,所以新加入的一定是某个节点的右儿子(或者直接当根),而那个节点之前的右儿子则变成这个节点的左儿子。其它位置则不会发生变化。

考虑到只有可能作为右儿子,所以一定是加在笛卡尔树的右链上(即从根节点一直往右走直到没有右儿子所组成的链)。而由于小根堆性质,右链单调不降,所以可以用一个单调栈维护右链,每次要加入一个节点就在右链上把所有大于其 value 的节点弹出,最后一个被弹出的成为新节点的左儿子(前提是有弹出),若栈里还有元素,则新节点为这个元素的右儿子。

洛谷模板题:

点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e7+50;
int N;
int p[MAXN];
int ls[MAXN],rs[MAXN];
int sta[MAXN],Top,Now;
long long ans1,ans2;
int Root;
int main()
{
	scanf("%d",&N);
	for(int i=1;i<=N;i++)
	{
		scanf("%d",&p[i]);
		Now=Top;
		while(Top&&p[sta[Top]]>p[i])
		{
			Top--;
		}
		if(Top)
		{
			rs[sta[Top]]=i;
		}
		if(Now^Top)
		{
			ls[i]=sta[Top+1];
		}
		sta[++Top]=i;
	}
	for(int i=1;i<=N;i++)
	{
		ans1^=(1ll*i*(ls[i]+1));
		ans2^=(1ll*i*(rs[i]+1));
	}
	printf("%lld %lld",ans1,ans2);
}

标签:index,下标,笛卡尔,int,Top,节点
From: https://www.cnblogs.com/0htoAi/p/16760466.html

相关文章

  • kruskal重构树and笛卡尔树
    为什么放在了一起因为我个人旗帜鲜明的认为这是一个东西前者可以旗帜鲜明的解决图上(包括树上)限定最值的联通问题建立方式:跑kruskal时每连接两个点时建立一个新点把原......
  • 笛卡尔树
    概念Link笛卡尔树的节点各有两个权值,其中一个权值满足二叉搜索树的性质,另一个满足小(大)根堆的性质。所以说Treap也是一种笛卡尔树。构造知乎以下均假设原序列元素......
  • 笛卡尔树
    笛卡尔树是一种二叉树,每个节点有两个键值\(x,y\),一个满足BST,一个满足堆。上图:一个性质是如果键值确定那么笛卡尔树是唯一的。笛卡尔树如果暴力构造很简单:找到整个序列......
  • 通过迭代工具itertools.product快速得到多列表笛卡尔积(列表组合)
    1.核心代码importitertoolssubject=['我想','我要']action=['打开','关闭']target=['电视','冰箱','洗衣机']forresinitertools.product(subject,ac......
  • python itertools库 itertools.product() 用法 产生多个序列的笛卡尔积
    python itertools.product()用来产生多个序列的笛卡尔积,参数可两个或者多个序列,元组tulple,列表list,range生成的序列,集合set都可作为参数1importitertools2#par......
  • 【模板】笛卡尔树
    笛卡尔树是一种二叉树,每个节点\(i\)由\(\left(k_i,w_i\right)\)构成,其中,\(k\)满足BST的性质,\(w\)满足堆的性质。若\(k,w\)互不相同,则构成的笛卡尔树唯一;两......