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

笛卡尔树

时间:2024-07-15 12:40:46浏览次数:6  
标签:cur 笛卡尔 int top 权值 define

笛卡尔树基本概念

笛卡尔树是基于一个静态序列 \(a\) 的,根据这个序列 \(a\),我们可以构造出对应的笛卡尔树。

笛卡尔树有三点要求需要满足:

  • 笛卡尔树是二叉树。

  • 笛卡尔树的编号的中序遍历为 \(1\sim n\),权值中序遍历为 \(a\)。

  • 笛卡尔树的权值满足大根堆或者小根堆的性质。

这里可以看一个图,节点上标的是权值。

为了更加方便,笛卡尔树的节点编号与序列 \(a\) 的下标编号共用。

笛卡尔树的构造

这里我们先给出笛卡尔树的性质:

  • 对于树上一条深度单调递增的路径,其权值单调不减。

  • \(\forall u,v;u\le v;p=\operatorname{lca}(u,v)=p\),以 \(p\) 为根的子树恰好涵盖 \(a\) 序列中 \([u,v]\) 区间的所有位置。

  • \(\forall u,v;u\le v;p=\operatorname{lca}(u,v)=p\),其在笛卡尔树上的最近公共祖先的权值 \(val_p\) 恰好为 \(a\) 序列中 \([u,v]\) 区间的最小值。

于是我们可以在线性时空内构造笛卡尔树。

我们考虑维护笛卡尔树上最右端的链,则有这条链的编号和权值都不减,于是我们可以用单调栈维护。

我们从前向后遍历 \(a\) 数组,设当前的位置为 \(i\),同时前 \(i-1\) 位的笛卡尔树已经构建完成,于是我们假设当前栈顶位置 \(top\),则当前栈顶元素为 \(s_{top}\),然后我们进行分类讨论。

  • \(a_i\ge a_{s_{top}}\),直接将 \(i\) 入栈。事实上就是在笛卡尔树的最右端的最下面插入这个元素。

  • 否则,开始弹出栈,直到栈为空或者栈顶元素权值不小于 \(a_i\),这里设最后一个弹出的元素的下标设为 \(j\)。则把 \(i\) 入栈,\(j\) 变为 \(i\) 的左儿子。

这里再挂个图,方便理解:

然后我们就建完树了,可以开始看题了。

笛卡尔树

考虑直接按照上面的步骤建树,维护一下左右儿子即可,没有需要特别注意的地方,所以直接放一下代码:

#include<bits/stdc++.h> 
#define int long long
#define pii pair<int,int>
#define x first
#define y second
#define N 10000005
using namespace std;
int n,a[N],stk[N],rt,res1,res2;
pii w[N];
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	int top=0,cur=0;
	for(int i=1;i<=n;i++){
		cur=top;
		while(top&&a[stk[cur]]>a[i])cur--;//弹栈
		if(cur)w[stk[cur]].y=i;//没弹完代表有东西更小,作为右儿子
		if(cur<top)w[i].x=stk[cur+1];//有东西出栈了,把出栈的最后一个节点作为当前点左儿子
		stk[++cur]=i;//入栈
		top=cur;
	}
	for(int i=1;i<=n;i++){
		res1^=(i*(w[i].x+1));
		res2^=(i*(w[i].y+1));
	}
	cout<<res1<<' '<<res2;
	return 0;
} 

树的序

类似于板子,说了这么多,其实就是对笛卡尔树求一个前序遍历,所以直接上代码:

#include<bits/stdc++.h> 
#define int long long
#define pii pair<int,int>
#define x first
#define y second
#define N 10000005
using namespace std;
int n,a[N],stk[N],rt,res1,res2;
pii w[N];
void dfs(int u){
	if(u==0)return;
	cout<<u<<' ';
	dfs(w[u].x);
	dfs(w[u].y);
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++){
		int x;
		cin>>x;
		a[x]=i;
	}
	int top=0,cur=0;
	for(int i=1;i<=n;i++){
		cur=top;
		while(top&&a[stk[cur]]>a[i])cur--;
		if(cur)w[stk[cur]].y=i;
		if(cur<top)w[i].x=stk[cur+1];
		stk[++cur]=i;
		top=cur;
	}
	dfs(stk[1]);
	return 0;
} 

标签:cur,笛卡尔,int,top,权值,define
From: https://www.cnblogs.com/zxh923aoao/p/18302853

相关文章

  • Franka 内部关节阻抗控制器和内部笛卡尔阻抗控制器的区别
    Franka机器人内部的关节阻抗控制器和笛卡尔阻抗控制器之间的本质区别如下:1.控制空间关节空间vs.笛卡尔空间:关节阻抗控制器工作在关节空间,即以关节角度、关节速度和关节扭矩为控制变量。笛卡尔阻抗控制器工作在笛卡尔空间,即以末端执行器的位置、速度和力作为控制变量。......
  • Franka libfranka 基于笛卡尔空间位置控制
    #include<array>#include<cmath>#include<iostream>#include<franka/exception.h>#include<franka/model.h>#include<franka/robot.h>#include<franka/tools.h>intmain(intargc,char**argv){try{//......
  • Franka libfranka 基于笛卡尔空间位置的运动控制
    #include<array>#include<cmath>#include<iostream>#include<franka/exception.h>#include<franka/model.h>#include<franka/robot.h>#include<franka/tools.h>intmain(intargc,char**argv){try{//......
  • P5854 【模板】笛卡尔树
    原题链接题解笛卡尔树的定义如下:任意一颗子树都代表一段连续的区间,且子树的根节点是该区间的最大值,根的左边的元素下标均比根小(二叉搜索树性质),子节点均比父节点大(堆的性质)我们讲如何实现的设即将要插入的元素为\(a_i\)栈内的元素为前\(i-1\)个元素构成的笛卡尔树从根一直......
  • 笛卡尔树
    笛卡尔树对于每个区间,找到区间的极值,把这个区间一分为二,这个极值就是这个区间的根,两个部分的根是极值的两个儿子如何求笛卡尔树?以大根堆为例方法一令\(l_i\)表示第\(i\)个元素向左第一个\(\ge\)它的位置,\(r_i\)表示第\(i\)个元素向右第一个\(\ge\)它......
  • 笛卡尔树
    引入首先我们看到这个序列\([9,4,10,1,7,2,3]\),现在我们找到它的最大值\(10\),并从中间劈开,此时分为了两个序列\([9,4]\)和\([1,7,2,3]\),接着对这两个序列继续这样的操作。现在,将劈开后序列最大值和被劈开的数建立父子关系,于是便建立了这个树:这也就是笛卡尔树。笛卡尔树满......
  • 基环树和笛卡尔树
    基环树就是比平常的树多一条边,有\(n\)条边,也就有一个环在里面。基本思想就是断环,跑树形\(dp\),或者用拓扑排序判环去跑环形\(dp\)。树的直径今天才了解到的,用两遍\(dfs\)跑。首先第一遍找到离根节点最远的节点\(u_1\),然后再从\(u_1\)找到离它最远的节点\(u_2\),那么......
  • 基环树和笛卡尔树
    1.基环树定义:有\(n\)个点和\(n\)条边的图,就是给树连了一条边,此时图中恰好只有一个环解决这类问题时,通常断环,变成普通的树的问题,然后再特殊处理环P2607[ZJOI2008]骑士click断环成树后就跟没上司一样是个树形dp,注意森林,longlong就行了,具体细节见这里P5022[NOIP2018提高组......
  • 过滤条件之分组 group by、having、distinct、order by、limit、正则、多表查询和子查
    【一】过滤条件之分组groupby【1】引入--按照指定条件对所有数据进行分组--对员工进行分组按照年龄/部门--...select*from*where*groupby*;【2】按照部门分组(1)查询数据select*fromempgroupbypost;#第一次使用部门分组会报错mysql>select*f......
  • 笛卡尔树
    笛卡尔树引入笛卡尔树是一种二叉树,每一个节点由一个键值二元组\((k,w)\)构成。要求k满足二叉搜索树的性质,而w满足堆的性质。一个有趣的事实是,如果笛卡尔树的\(k,w\)键值确定,且k互不相同,w互不相同,那么这个笛卡尔树的结构是唯一的。上面这棵笛卡尔树相当于把数组元素当作键值w,......