浅谈笛卡尔树
[介绍(百度百科)](笛卡尔树_百度百科 (baidu.com))
笛卡尔树是一种特定的二叉树数据结构,可由数列构造,在范围最值查询、范围
特殊的
性质
先说性质感觉会更好理解一些
虽然是"树",但是笛卡尔树其实就是对序列的一个转化
对于树上的任意一点x,左右儿子left,right,以及在原序列上的
- 树中的元素满足二叉搜索树的性质,要求按照中序遍历得到的序列为原数组序列,各节点的
是连续的, ,(维持原序列的顺序) - 树中节点满足堆性质,节点的
值要大于其左右子节点的 值, ,(大根此时则恰恰相反)
对于笛卡尔树中每个节点都有两个权值
建树
可以使用线段树,st表这些数据结构维护区间最大值/最小值,但是没有必要,大多数笛卡尔树的题目都可以通过维护一个单调栈来实现
- 使用单调栈维护最右链
- 每次插入当前的
,在单调栈中不停弹出栈顶,直至栈顶 满足 ,则最后一次弹出的就是 - 将
作为 的右儿子, 作为 的左儿子
模拟一下就是:
对于序列
- 添加点
, 加入栈 - 添加点
,弹出点 ,点 就是 的左儿子,将 加入栈,成为栈顶 - 添加点
, ,故成为点 的右儿子 - .................(见图)
[P5854 【模板】笛卡尔树](P5854 【模板】笛卡尔树 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn))
模板题,求建出树后就可以得到
#include"bits/stdc++.h"
using namespace std;
const int N=1e7+15;
#define inl inline
#define regi register
#define PII pair<int,int>
//#define ll long long
inl int read(void)
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) f=ch=='-'?-1:f,ch=getchar();
while(isdigit(ch)) x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
int rt;int ls[N],rs[N],fa[N],n;
void build(int* a)
{
stack<int> sta;stack<int>().swap(sta);
for(int i=1;i<=n;i++)
{
int j=0;
while(!sta.empty()&&a[sta.top()]>a[i]) j=sta.top(),sta.pop();
if(sta.empty()) rt=i;
else rs[sta.top()]=i;
ls[i]=j;
sta.push(i);
}
}
int p[N],tot=0;
stack<int> sta;
void insert(int val)
{
p[++tot]=val;
int i=tot;
while(!sta.empty()&&p[sta.top()]>p[i]) sta.pop();
if(!sta.empty())
fa[i]=sta.top(),rs[sta.top()]=i,ls[i]=i-1;
else ls[i]=rt,rt=i;
sta.push(i);
}
struct RMQ
{
int L,R,dep[10015],sz[10015],ans;
int dfs1(int u)
{
dep[u]=dep[fa[u]]+1;
if(ls[u]) dfs1(ls[u]);
if(rs[u]) dfs1(rs[u]);
sz[u]+=sz[ls[u]],sz[u]+=sz[rs[u]];
}//lca(l,r)=min(val_l,val_r),dfs1->get_dep
RMQ(int l,int r):L(l),R(r){memset(dep,0,sizeof dep),memset(sz,0,sizeof sz);};
int get_RMQ(void)
{
int l=L,r=R;dfs1(1);
int u=l,v=r;
while(dep[u]!=dep[v])
{
if(dep[u]<dep[v]) swap(u,v);
u=fa[u];
}
ans=u;
}//log_2 n
};
int a[N];
int main(void)
{
n=read();
for(int i=1;i<=n;i++) a[i]=read();
build(a);
long long ans1=0,ans2=0;
for(int i=1;i<=n;i++) ans1^=1ll*i*(ls[i]+1),ans2^=1ll*i*(rs[i]+1);
printf("%lld %lld",ans1,ans2);
return 0;
}
[P4755 Beautiful Pair](P4755 Beautiful Pair - 洛谷 | 计算机科学教育新生态 (luogu.com.cn))
有一个数列
有很多人使用的都是线段树分治,但是提到笛卡尔树了,就写一下笛卡尔树分治
笛卡尔树在这些区间最值的地方有着非常不错的性质,考虑分治,区间为
建出笛卡尔树,可以很容易发现,贡献都是
1.max的左子树的贡献
2.max的右子树的贡献
3.右边对左边的贡献
再维护一个树状数组
时间复杂度为
#include"bits/stdc++.h"
using namespace std;
const int N=1e5+15,M=1e9+15;
#define inl inline
#define regi register
#define PII pair<int,int>
#define int long long
inl int read(void)
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) f=ch=='-'?-1:f,ch=getchar();
while(isdigit(ch)) x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
int rt;
struct node
{
int ls,rs;
}tr[N];
int n;
void build(int* a)
{
stack<int> sta;stack<int>().swap(sta);
for(int i=1;i<=n;i++)
{
int j=0;
while(!sta.empty()&&a[sta.top()]<a[i]) j=sta.top(),sta.pop();
if(sta.empty()) rt=i;
else tr[sta.top()].rs=i;
tr[i].ls=j;
sta.push(i);
}
}
int ans;
int siz,a[N],b[N];
long long c[N];
#define lowbit(x) x&(-x)
void add(int x,int k){for(;x<=n;x+=lowbit(x))c[x]+=k;}
int query(int x){long long res=0;for(;x;x-=lowbit(x))res+=c[x];return res;}
void solve(int u,int l,int r)
{
if(u==0) return ;
int ls=tr[u].ls,rs=tr[u].rs;
int mid=u;
if(mid-l>r-mid)
{
for(int i=mid;i<=r;i++)
{
int x=upper_bound(b,b+siz+1,b[a[mid]]/b[a[i]])-b;
if(x) ans-=query(x-1);
}
solve(ls,l,mid-1),add(a[mid],1);
for(int i=mid;i<=r;i++)
{
int x=upper_bound(b,b+siz+1,b[a[mid]]/b[a[i]])-b;
if(x) ans+=query(x-1);
}
solve(rs,mid+1,r);
}
else
{
for(int i=l;i<=mid;i++)
{
int x=upper_bound(b,b+siz+1,b[a[mid]]/b[a[i]])-b;
if(x) ans-=query(x-1);
}
solve(rs,mid+1,r),add(a[mid],1);
for(int i=l;i<=mid;i++)
{
int x=upper_bound(b,b+siz+1,b[a[mid]]/b[a[i]])-b;
if(x) ans+=query(x-1);
}
solve(ls,l,mid-1);
}
}
signed main(void)
{
n=read();
for(int i=1;i<=n;i++) b[i]=a[i]=read();
sort(b+1,b+1+n);
siz=unique(b+1,b+1+n)-b-1;
for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+1+siz,a[i])-b;
build(a);
solve(rt,1,n);
printf("%lld",ans);
return 0;
}
本文来自博客园,作者:Ech0_7,转载请注明原文链接:https://www.cnblogs.com/empty-space/p/18441111
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架