笛卡尔树
概念
一个区间的最小值作为根节点,然后左子树就是最小值左边区间的点,右子树是最小值右边区间的点,然后也是同理,左子树的根是左边区间的最小值,右子树一致
性质
板子:
int a[N],l[N],r[N],root,n;
void build(){
//单调栈维护右链
stack<int> st;
for(int i=1;i<=n;i++){
int last=0;
while(!st.empty()&&a[st.top()]>a[i]){
last=st.top();
st.pop();
}
if(!st.empty()) r[st.top()]=i;
else root=i;
l[i]=last;
st.push(i);
}
}
例题:
首先可以发现一个性质就是,如果对于任意区间来说,两个排列的最小值位置是一样的,那么就可以说明这两个排列的笛卡尔树的形态应当是一致的
然后贪心填值,到最后,字典序一定是最小的
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define x first
#define y second
#define int long long
const int N=1e6+5,mod=998244353;
int a[N],l[N],r[N],root,n,ans[N],tot;
void dfs(int u){
ans[u]=++tot;
if(l[u])dfs(l[u]);
if(r[u])dfs(r[u]);
}
void build(){
//单调栈维护右链
stack<int> st;
for(int i=1;i<=n;i++){
int last=0;
while(!st.empty()&&a[st.top()]>a[i]){
last=st.top();
st.pop();
}
if(!st.empty()) r[st.top()]=i;
else root=i;
l[i]=last;
st.push(i);
}
dfs(root);
}
void slove(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
build();
for(int i=1;i<=n;i++) cout<<ans[i]<<" ";
cout<<endl;
}
signed main(){
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
int T=1;
while(T--) slove();
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架