CF1290E Cartesian Tree
时间:2020-07-15
本文章向大家介绍CF1290E Cartesian Tree,主要包括CF1290E Cartesian Tree使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
题意:
笛卡尔树是一种既满足堆的性质,又满足二叉搜索树的性质的树。可以发现的是,对于一个排列,它的笛卡尔树是唯一的。
\(n \leq 2\times 10^5\)。
题解:发现笛卡尔树中的一个节点的权值可以表示为\(r_i-l_i+1\)的形式。其中\(r_i\)表示最小的\(p \geq i\),使得\(a_{p+1}>a_i\)。所以我们可以分别维护\(l_i\)和\(r_i\)。
考虑加入一个权值最大的点后,\(r_i\)和\(l_i\)会出现哪些变化。设当前插入的是数字\(i\),它在排列中的位置是\(p\),它在当前的由1到\(i\)组成的子序列中的位置为\(q\)。
- 对于\(\forall_{k<p}\),\(r_k=min(r_k,q-1)\);
- 对于\(p\),\(l_p=1,r_p=i\)。
- 对于\(\forall_{k>p},l_k++,r_k++,l_k=max(l_k,q+1)\)。
所以相当于是区间取min,区间加和单点赋值。我们可以采用势能线段树的思想,维护:
- 区间和;
- 最大(小)值;
- 最大(小)值出现次数;
- 次大(小)值;
- 区间合法点个数;
- 加法标记和赋值标记。
对于区间取min操作,我们递归到一个区间,其最大值小于\(w\),次大值大于等于\(w\)时进行修改,否则继续递归子树。
不会势能线段树区间取min复杂度证明的可以出门右转自行百度。
注意pushup和pushdown各要分三种情况讨论,还要注意标记的下传顺序问题。
时间复杂度:\(O(nlog^2n)\)。
代码:
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define F(x,y,z) for(re x=y;x<=z;x++)
#define FOR(x,y,z) for(re x=y;x>=z;x--)
typedef long long ll;
#define I inline void
#define IN inline int
#define C(x,y) memset(x,y,sizeof(x))
#define STS system("pause")
template<class D>I read(D &res){
res=0;register D g=1;register char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')g=-1;
ch=getchar();
}
while(isdigit(ch)){
res=(res<<3)+(res<<1)+(ch^48);
ch=getchar();
}
res*=g;
}
const int INF=1e9+7;
int n,m,a[202000],p[202000],t[202000];
IN lbt(int x){return x&(-x);}
I modi(int x,int w){while(x<=n)t[x]+=w,x+=lbt(x);}
IN ques(int x){re res=0;while(x)res+=t[x],x-=lbt(x);return res;}
#define all 1,1,n
#define lt k<<1,l,mid
#define rt k<<1|1,mid+1,r
ll sr[1606000],sl[1606000];int cntr[1606000],cntl[1606000];
int mxr[1606000],mxl[1606000],smxr[1606000],smxl[1606000],cmxr[1606000],cmxl[1606000],snl[1606000],snr[1606000];
int lazr[1606000],lazl[1606000],lmr[1606000],lml[1606000];
I build(int k,int l,int r){
sl[k]=sr[k]=cntr[k]=cntl[k]=cmxr[k]=cmxl[k]=lazr[k]=lazl[k]=lmr[k]=lml[k]=0;
mxr[k]=smxr[k]=-INF;mxl[k]=smxl[k]=INF;
if(l==r)return;
re mid=(l+r)>>1;
build(lt);build(rt);
}
I push_upl(int k){
sl[k]=sl[k<<1]+sl[k<<1|1];cntl[k]=cntl[k<<1]+cntl[k<<1|1];
if(mxl[k<<1]<mxl[k<<1|1]){
snl[k]=1;
mxl[k]=mxl[k<<1];cmxl[k]=cmxl[k<<1];smxl[k]=min(smxl[k<<1],mxl[k<<1|1]);
}
else if(mxl[k<<1]>mxl[k<<1|1]){
snl[k]=2;
mxl[k]=mxl[k<<1|1];cmxl[k]=cmxl[k<<1|1];smxl[k]=min(smxl[k<<1|1],mxl[k<<1]);
}
else{
snl[k]=3;
mxl[k]=mxl[k<<1];cmxl[k]=cmxl[k<<1]+cmxl[k<<1|1];smxl[k]=min(smxl[k<<1],smxl[k<<1|1]);
}
}
I push_upr(int k){
sr[k]=sr[k<<1]+sr[k<<1|1];cntr[k]=cntr[k<<1]+cntr[k<<1|1];
if(mxr[k<<1]>mxr[k<<1|1]){
snr[k]=1;
mxr[k]=mxr[k<<1];cmxr[k]=cmxr[k<<1];smxr[k]=max(smxr[k<<1],mxr[k<<1|1]);
}
else if(mxr[k<<1]<mxr[k<<1|1]){
snr[k]=2;
mxr[k]=mxr[k<<1|1];cmxr[k]=cmxr[k<<1|1];smxr[k]=max(smxr[k<<1|1],mxr[k<<1]);
}
else{
snr[k]=3;
mxr[k]=mxr[k<<1];cmxr[k]=cmxr[k<<1]+cmxr[k<<1|1];smxr[k]=max(smxr[k<<1],smxr[k<<1|1]);
}
}
I add_l(int k,int w){
sl[k]+=(ll)cntl[k]*w;if(mxl[k]!=INF)mxl[k]+=w;if(smxl[k]!=INF)smxl[k]+=w;lazl[k]+=w;
}
I maxl(int k,int w){
if(lazl[k]){
add_l(k<<1,lazl[k]);add_l(k<<1|1,lazl[k]);lazl[k]=0;
}
sl[k]+=(ll)cmxl[k]*(w-mxl[k]);mxl[k]=cmxl[k]?w:INF;lml[k]=w;
}
I push_downl(int k){
if(lml[k]){
if(snl[k]^2)maxl(k<<1,lml[k]);
if(snl[k]^1)maxl(k<<1|1,lml[k]);
lml[k]=0;
}
if(lazl[k]){
add_l(k<<1,lazl[k]);add_l(k<<1|1,lazl[k]);lazl[k]=0;
}
}
I add_r(int k,int w){
sr[k]+=(ll)cntr[k]*w;if(mxr[k]!=-INF)mxr[k]+=w;if(smxr[k]!=-INF)smxr[k]+=w;lazr[k]+=w;
}
I minr(int k,int w){
if(lazr[k]){
add_r(k<<1,lazr[k]);add_r(k<<1|1,lazr[k]);lazr[k]=0;
}
sr[k]+=(ll)cmxr[k]*(w-mxr[k]);mxr[k]=cmxr[k]?w:-INF;lmr[k]=w;
}
I push_downr(int k){
if(lmr[k]){
if(snr[k]^2)minr(k<<1,lmr[k]);
if(snr[k]^1)minr(k<<1|1,lmr[k]);
lmr[k]=0;
}
if(lazr[k]){
add_r(k<<1,lazr[k]);add_r(k<<1|1,lazr[k]);lazr[k]=0;
}
}
I modi_l(int k,int l,int r,int x,int w){
if(l==r){
sl[k]=mxl[k]=w;smxl[k]=INF;cmxl[k]=cntl[k]=1;
return;
}
push_downl(k);
re mid=(l+r)>>1;
if(x<=mid)modi_l(lt,x,w);
else modi_l(rt,x,w);
push_upl(k);
}
I modi_r(int k,int l,int r,int x,int w){
if(l==r){
sr[k]=mxr[k]=w;smxr[k]=-INF;cmxr[k]=cntr[k]=1;
return;
}
push_downr(k);
re mid=(l+r)>>1;
if(x<=mid)modi_r(lt,x,w);
else modi_r(rt,x,w);
push_upr(k);
}
I revi_l(int k,int l,int r,int x,int y,int w){
if(x>r||y<l||!cntl[k])return;
if(x<=l&&r<=y)return add_l(k,w),void();
push_downl(k);
re mid=(l+r)>>1;
revi_l(lt,x,y,w);revi_l(rt,x,y,w);
push_upl(k);
}
I revi_r(int k,int l,int r,int x,int y,int w){
if(x>r||y<l||!cntr[k])return;
if(x<=l&&r<=y)return add_r(k,w),void();
push_downr(k);
re mid=(l+r)>>1;
revi_r(lt,x,y,w);revi_r(rt,x,y,w);
push_upr(k);
}
I fill_max(int k,int l,int r,int x,int y,int w){
if(x>r||y<l||!cntl[k]||mxl[k]>=w)return;
if(x<=l&&r<=y){
if(smxl[k]>=w){
// cout<<"#"<<l<<" "<<r<<" "<<w<<endl;
return maxl(k,w),void();
}
push_downl(k);
re mid=(l+r)>>1;
fill_max(lt,x,y,w);fill_max(rt,x,y,w);
return push_upl(k),void();
}
push_downl(k);
re mid=(l+r)>>1;
fill_max(lt,x,y,w);fill_max(rt,x,y,w);
push_upl(k);
}
I fill_min(int k,int l,int r,int x,int y,int w){
if(x>r||y<l||!cntr[k]||mxr[k]<=w)return;
if(x<=l&&r<=y){
if(smxr[k]<=w){
// cout<<"@"<<l<<" "<<r<<" "<<w<<endl;
return minr(k,w),void();
}
push_downr(k);
re mid=(l+r)>>1;
fill_min(lt,x,y,w);fill_min(rt,x,y,w);
return push_upr(k),void();
}
push_downr(k);
re mid=(l+r)>>1;
fill_min(lt,x,y,w);fill_min(rt,x,y,w);
push_upr(k);
}
I getit(int k,int l,int r){
cout<<"!"<<k<<" "<<l<<" "<<r<<" "<<sl[k]<<" "<<sr[k]<<" "<<mxl[k]<<" "<<mxr[k]<<" "<<smxl[k]<<" "<<smxr[k]<<" "<<cmxl[k]<<" "<<cmxr[k]<<endl;
if(l==r)return ;//cout<<k<<" "<<l<<" "<<r<<" "<<sl[k]<<" "<<sr[k]<<endl,void();
push_downl(k);push_downr(k);
re mid=(l+r)>>1;
getit(lt);getit(rt);
}
int main(){
// freopen("a.out","w",stdout);
read(n);F(i,1,n)read(a[i]),p[a[i]]=i;build(all);
F(i,1,n){
modi_l(all,p[i],1),modi_r(all,p[i],i);
m=ques(p[i])+1;modi(p[i],1);revi_l(all,p[i]+1,n,1);revi_r(all,p[i]+1,n,1);
fill_max(all,p[i]+1,n,m+1);fill_min(all,1,p[i]-1,m-1);
printf("%lld\n",sr[1]-sl[1]+i);
// getit(all);
}
return 0;
}
/*
5
2 4 1 5 3
6
1 2 4 5 6 3
10
8 10 9 3 7 5 4 6 2 1
15
1 7 12 14 15 9 8 10 11 2 5 4 3 13 6
*/
原文地址:https://www.cnblogs.com/Purple-wzy/p/13308506.html
- 1854: [Scoi2010]游戏
- Javascript字符串
- Codevs3278[NOIP2013]货车运输
- 关于使用lazytag的线段树两种查询方式的比较研究
- Java 持久化操作之 --XML
- 算法模板——splay区间反转 1
- 3223: Tyvj 1729 文艺平衡树
- 1212: [HNOI2004]L语言
- POJ 2942Knights of the Round Table(tarjan求点双+二分图染色)
- 算法模板——平衡树Treap
- Java并发编程
- 算法模板——线段树2(区间加+区间乘+区间求和)
- 1798: [Ahoi2009]Seq 维护序列seq
- 【LeetCode 389】 关关的刷题日记30 Find the Difference
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 【即时通信IM】红包消息如何构建?
- YOLOv4损失函数全面解析
- Pandas进阶修炼120题,给你深度和广度的船新体验
- 5万字、97 张图总结操作系统核心知识点
- C++核心准则CP.100:不要使用无锁编程方式,除非绝对必要
- 神了,Excel的这个操作我今天才知道
- DataFrame(7):DataFrame运算——逻辑运算
- 高性能网关设计实践
- LASSO回归姊妹篇:R语言实现岭回归分析
- 学了这个,三歪再也不想写各种setter了
- 使用 GitLab CI 与 Argo CD 进行 GitOps 实践
- Java 语言中十大“坑爹”功能!
- 面试:说说啥是一致性哈希算法?
- 问一下,线程池里面到底该设置多少个线程?
- 进程和线程基础知识全家桶,30 张图一套带走