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

笛卡尔树

时间:2023-05-25 20:33:39浏览次数:33  
标签:右链 笛卡尔 int top stk 键值

笛卡尔树

下文的资料多摘自OI Wiki

性质

笛卡尔树是一种二叉树,每一个节点都由一个键值二元组 \((k,w)\) 构成。要求 \(k\) 满足二叉搜索树的性质,而 \(w\) 满足堆的性质。如果笛卡尔树的 \(k\) ,\(w\) 键值确定的话,且 \(k\) 互不相同,\(w\) 互不相同,那么这个笛卡尔树的结构是唯一的。

例如:

image

上面的这棵树是按每一个点内的值为键值 \(w\),把数组下标当作键值 \(k\),来建立的。仔细观察可以发现,这棵树的 \(k\) 满足二叉搜索树的性质,而键值 \(w\) 是满足小根堆的性质的。

我们由此可以看出,笛卡尔树就是一种键值不随机的 Treap。

构建

过程

我们考虑将元素的键值 \(k\) 进行排序,然后一个一个地插入到当前的笛卡尔树中,那么我们每一次插入的元素必在这个树的右链(右链:从根节点一直往右子树走,经过的节点)的末端。于是我们可以执行这样一个过程,从下往上比较右链节点与当前节点的 \(u\),和\(w\),如果找到了一个右链上的节点满足 \(x_{w}<u_{w}\),就把 \(u\) 接到 \(x\) 的有儿子上,而 \(x\) 原来的右子树就变成了 \(u\) 的左子树。

image

显然每个数最多进出右链一次。这个过程我们可以用栈维护,栈中维护当前笛卡尔树的右链上的结点。这样每个点最多进出一次,复杂度 \(O(n)\)。

更简易的去理解:我们用栈去维护右链,使得 \(k\) 满足二叉搜索树,而为了满足小根堆的状态,我们如果遇到了下面 \(w\) 小上面 \(w\) 大的情况,就不断的进行平衡树中类似的左旋操作,把 \(w\) 小的旋上去,使它满足小根堆的性质。

实现

stk[++top] = 1;
for(re int i=2;i<=n;i++) 
{
	while(top && a[stk[top]] > a[i]) top--;
	if(!top) ls[i] = stk[1];
	else ls[i] = rs[stk[top]] , rs[stk[top]] = i;
	stk[++top] = i;
}

P5854 【模板】笛卡尔树

#include<bits/stdc++.h>
//#define int long long
#define ll long long
#define next nxt
#define re register
#define il inline
const int N = 1e7 + 5;
using namespace std;
int max(int x,int y){return x > y ? x : y;}
int min(int x,int y){return x < y ? x : y;}

int a[N],stk[N],ls[N],rs[N];
int n,top;
ll ans1,ans2;

il int read()
{
	int f=0,s=0;
	char ch=getchar();
	for(;!isdigit(ch);ch=getchar()) f |= (ch=='-');
	for(; isdigit(ch);ch=getchar()) s = (s<<1) + (s<<3) + (ch^48);
	return f ? -s : s;
}

signed main()
{
	n = read();
	for(re int i=1;i<=n;i++) a[i] = read();
	stk[++top] = 1;
	for(re int i=2;i<=n;i++) 
	{
		while(top && a[stk[top]] > a[i]) top--;
		if(!top) ls[i] = stk[1];
		else ls[i] = rs[stk[top]] , rs[stk[top]] = i;
		stk[++top] = i;
	}
	for(re int i=1;i<=n;i++)
	{
		ans1 ^= (1ll * i * (ls[i]+1));
		ans2 ^= (1ll * i * (rs[i]+1));
	}
	cout << ans1 << " " << ans2;
	return 0;
}

笛卡尔树一般就是快速解决区间 \(RMQ\) 问题,但是它是个很鸡肋的存在,大多数情况下用不上这个数据结构。

标签:右链,笛卡尔,int,top,stk,键值
From: https://www.cnblogs.com/bloodstalk/p/17432787.html

相关文章

  • 笛卡尔树Kattis-Scaffolding
    笛卡尔树Kattis-Scaffolding注释已经写在代码里了,注意下建树就行#include<bits/stdc++.h>/*先对题意进行分析,每次带m根柱子,进行x轮,每次往左/右/上搭建,问x的最小值?一开始在想,怎么就会有最小值呢?后来发现题目说不能往下走我们还是把图看成一棵树就是说你可以向两个子节点去走,......
  • 笛卡尔树
    性质其节点具有\(2\)个权值,分别是\((key,val)\),以\(key\)看,其为一颗二叉搜索树,以\(val\)看,其为一个堆(定义)。二叉搜索树:左子树如果不空,则其权值一定小于根节点;右子树如果不空,则其权值一定大于根节点。堆:完全二叉树,每个节点的值大于等于(或小于等于)其子树中的每个节......
  • @黎耀天 发扬 笛卡尔, @物空必能 发扬 牛顿, 无敌了 。
    @黎耀天发扬笛卡尔, @物空必能发扬牛顿,  @joywee2007 发扬爱因斯坦和老子,  无敌了 。 这篇文章的灵感来自 昨前天 看到 @物空必能在牛顿吧发的 《物质的弹性与屈服强度——力学就应当探究力的问题》    https://tieba.baidu.com/p/83932......
  • C++ 树进阶系列之笛卡尔树的两面性
    1.前言笛卡尔树是一种特殊的二叉树数据结构,融合了二叉堆和二叉搜索树两大特性。笛卡尔树可以把数列(组)对象映射成二叉树,便于使用笛卡尔树结构的逻辑求解数列的区间最值或......
  • 笛卡尔树~cartesian-tree
    笛卡尔树简介笛卡尔树是一种平衡树,它的结构和treap相同,但是由于它能在O(n)时间构造,同时具有一些很有意思的性质。构造笛卡尔树的节点由键值对\((k,w)\)组成。其中键......
  • 笛卡尔树
    笛卡尔树总述笛卡尔树是一种二叉树,每一个结点由一个键值二元组\((k,w)\)构成。要求\(k\)满足二叉搜索树的性质,而\(w\)满足堆的性质,如果笛卡尔树的\(k,w\)键值确......
  • 动态笛卡尔树
    这里讲的动态笛卡尔树的问题指的是你要对一个序列单点加值并维护笛卡尔树的形态信息。由于具有严格偏序关系的数列对应的笛卡尔树唯一,我们只需要像维护Treap一样单点上......
  • 【YBT2023寒假Day12 B】仰望星空(DP)(线段树)(笛卡尔树)
    仰望星空题目链接:YBT2023寒假Day12B题目大意有一个n*n的网格,第i列下面的ai个点都是障碍。然后又一些不是障碍的地方有特殊点,删掉它有费用。要你用最小费用使得......
  • 为笛卡尔积运算而生的Reduce(Excel函数集团)
    我要是没记错,Reduce这词是减少的意思,可是当他作为Excel函数出现时,我真没看出哪里Reduce了……好吧,其实可以换种理解,缩减了嵌套(帮助里写的是“将数组缩减为累计值)。来来来......
  • left join(左连接)、right join(右连接)、full join(全连接)、inner join(内连接)、cr
    (1)leftjoin(左连接)在两张表进行连接查询时,会返回左表所有的行数据,右表中返回只返回和左表匹配的数据,没有的显示为Null。(2)rightjoin(右连接)在两张表进行连接查询时,会返......