知识点 - 笛卡尔树
解决问题类型:
笛卡尔树同时满足两个性质,从key来看,满足二叉搜索树的特性,从value来看,满足堆的性质
1. 建树复杂度低
2. 查询区间最大最小值
复杂度:
建树 $ O(N) $
查找结点 O ( l o g N ) O(logN) O(logN)
例题
Removing Stones(笛卡尔树 分治)
代码
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
const int maxn=3e5+5;
int a[maxn];
int rt,ls[maxn],rs[maxn];
int top;
int sta[maxn];
bool vis[maxn];
void init(int n){
int tmp;
top=0;
rep(i,1,n){
vis[i]=0;
ls[i]=rs[i]=0;
}
rep(i,1,n){
vis[i]=0;
// 位置0存左边的最大值
tmp=top;
// 栈内递减,找第一个比新的数大的
while(tmp&&a[sta[tmp-1]]<a[i])tmp--;
// 找到了为tmp-1位置,rs[stk[tmp-1]]=i
if(tmp)rs[sta[tmp-1]]=i;
// 因为tmp和top实际为栈顶位置+1,所以只要栈顶元素小于当前元素,则说明存在ls,tmp指向最大的小于当前元素的值
if(top>tmp)ls[i]=sta[tmp];
// 小的元素出栈,新值入栈
sta[tmp++]=i;
top=tmp;
}
rep(i,1,n){
vis[ls[i]]=vis[rs[i]]=1;
}
rep(i,1,n){
if(!vis[i]){
rt=i;break;
}
}
}
int main(){
int t;scanf("%d",&t);
while(t--){
int n;scanf("%d",&n);
rep(i,1,n){
scanf("%d",&a[i]);
}
init(n);
}
}