CF1290E Cartesian Tree

II.I.CF1290E Cartesian Tree

并非一道很板的题,但是是可以被想出的。

考虑把笛卡尔树求出其中序遍历,则每个节点的子树是上面一段区间 [li,ri]

考虑往中序遍历序列中某个位置 p 之后插入一个数 k。显然,依照定义,这个数必定大于原序列中所有数。考虑插入后每个 [li,ri] 的变化。

我们发现,对于 pp 左侧的所有位置 i,其 li 不变,ripmin;对于新插入的这个数本身,其 l=1r=k;对于 p 右侧所有 i,因为多插入了一个数,所以所有 l,r 先增加 1,然后 lp+2max

我们发现,因为我们要求的是 i=1krili+1,故其可以被拆成 (r)(l)+kr 可简单维护,而 l 在整个序列翻转后,便可以同 r 一样求出,两者求和后只需在最后减去一个 k2 就行了。

于是我们只需处理对于 r 的操作就行了。

我们发现,要执行的是前缀取 min,单点赋值,后缀 +1。则直接吉司机线段树就搞定了。

需要注意的是,没有被赋值过的位置要被忽略,就像动态开点线段树里面的空子树一样处理。

因为这里有后缀加,所以复杂度有 nlog2n 的上界。然而根本跑不满,所以吉司机线段树大可以在 5×105 这种数据范围下随便用,特别是在本题还是 1.5×1055s 的。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,a[150100],p[150100];
ll res[150100];
#define lson x<<1
#define rson x<<1|1
#define mid ((l+r)>>1)
struct SegBeat{
	int mx,mmx,mxc,tag,gat,sz;ll sum;
	SegBeat(){sum=tag=-1,sz=gat=0;}
}seg[600100];
void pushup(int x){
	if(seg[lson].sum==-1&&seg[rson].sum==-1){seg[x].sum=-1;return;}
	if(seg[lson].sum==-1){seg[x]=seg[rson],seg[x].gat=0,seg[x].tag=-1;return;}
	if(seg[rson].sum==-1){seg[x]=seg[lson],seg[x].gat=0,seg[x].tag=-1;return;}
	seg[x].mx=max(seg[lson].mx,seg[rson].mx),seg[x].mmx=-1,seg[x].mxc=0,seg[x].sum=seg[lson].sum+seg[rson].sum,seg[x].sz=seg[lson].sz+seg[rson].sz;
	if(seg[x].mx!=seg[lson].mx)seg[x].mmx=max(seg[x].mmx,seg[lson].mx);else seg[x].mxc+=seg[lson].mxc,seg[x].mmx=max(seg[x].mmx,seg[lson].mmx);
	if(seg[x].mx!=seg[rson].mx)seg[x].mmx=max(seg[x].mmx,seg[rson].mx);else seg[x].mxc+=seg[rson].mxc,seg[x].mmx=max(seg[x].mmx,seg[rson].mmx);
}
void MOD(int x,int y){seg[x].sum-=1ll*(seg[x].mx-y)*seg[x].mxc,seg[x].mx=seg[x].tag=y;}
void ADD(int x,int y){seg[x].mx+=y,seg[x].gat+=y,seg[x].mmx+=y,seg[x].sum+=1ll*seg[x].sz*y;if(seg[x].tag!=-1)seg[x].tag+=y;}
void pushdown(int x){
	if(seg[lson].sum!=-1)ADD(lson,seg[x].gat);
	if(seg[rson].sum!=-1)ADD(rson,seg[x].gat);
	seg[x].gat=0;
	if(seg[x].tag==-1)return;
	if(seg[lson].sum!=-1&&seg[lson].mx>seg[x].tag)MOD(lson,seg[x].tag);
	if(seg[rson].sum!=-1&&seg[rson].mx>seg[x].tag)MOD(rson,seg[x].tag);
	seg[x].tag=-1;
}
void modifypos(int x,int l,int r,int P,int val){
	if(l>P||r<P)return;
	if(l==r){seg[x].mx=val,seg[x].mmx=-1,seg[x].sum=val,seg[x].mxc=1,seg[x].sz=1;return;}
	pushdown(x),modifypos(lson,l,mid,P,val),modifypos(rson,mid+1,r,P,val),pushup(x);
}
void modifymn(int x,int l,int r,int L,int R,int val){
	if(seg[x].mx<=val||seg[x].sum==-1||l>R||r<L)return;
	if(L<=l&&r<=R&&seg[x].mmx<val){MOD(x,val);return;}
	pushdown(x),modifymn(lson,l,mid,L,R,val),modifymn(rson,mid+1,r,L,R,val),pushup(x);
}
void modifyshift(int x,int l,int r,int L,int R){
	if(l>R||r<L||seg[x].sum==-1)return;
	if(L<=l&&r<=R){ADD(x,1);return;}
	pushdown(x),modifyshift(lson,l,mid,L,R),modifyshift(rson,mid+1,r,L,R),pushup(x);
}
void clear(int x,int l,int r){
	seg[x]=SegBeat();
	if(l!=r)clear(lson,l,mid),clear(rson,mid+1,r);
}
/*void iterate(int x,int l,int r){
	if(seg[x].sum==-1)return;
	printf("[%d,%d]:MX:%d CM:%d MM:%d SM:%d SZ:%d GT:%d TG:%d\n",l,r,seg[x].mx,seg[x].mxc,seg[x].mmx,seg[x].sum,seg[x].sz,seg[x].gat,seg[x].tag);
	if(l!=r)iterate(lson,l,mid),iterate(rson,mid+1,r);
}
void etareti(int x,int l,int r){
	if(seg[x].sum==-1)return;
	if(l!=r)pushdown(x),etareti(lson,l,mid),etareti(rson,mid+1,r),pushup(x);
	else printf("(%d:%d)",l,seg[x].mx);
}*/
int t[200100];
void BITADD(int x){while(x<=n)t[x]++,x+=x&-x;}
int BITSUM(int x){int ret=0;while(x)ret+=t[x],x-=x&-x;return ret;}
void func(){
	clear(1,1,n),memset(t,0,sizeof(t));
	for(int i=1;i<=n;i++){
		int Rmax=BITSUM(p[i]);
		modifymn(1,1,n,1,p[i]-1,Rmax);
		modifypos(1,1,n,p[i],i);
		modifyshift(1,1,n,p[i]+1,n);
//		printf("%d\n",seg[1].sum);
		res[i]+=seg[1].sum;
		BITADD(p[i]);
//		iterate(1,1,n),puts("");
//		etareti(1,1,n),puts("");
//		iterate(1,1,n),puts("");
	}
}
inline void read(int &x){
	x=0;
	char c=getchar();
	while(c>'9'||c<'0')c=getchar();
	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
}
inline void print(ll x){
	if(x<=9)putchar('0'+x);
	else print(x/10),putchar('0'+x%10);
}
int main(){
	read(n);
	for(int i=1;i<=n;i++)read(a[i]),p[a[i]]=i;
	func();
	reverse(a+1,a+n+1);for(int i=1;i<=n;i++)p[a[i]]=i;
	func();
	for(int i=1;i<=n;i++)print(res[i]-1ll*i*i),putchar('\n');
	return 0;
}
posted @   Troverld  阅读(82)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示