CF1290E Cartesian Tree 注意点--zhengjun

发布时间 2023-07-13 21:55:01作者: A_zjzj

解题思路

容易想到从小到大加数,维护每个点的子树大小。

可转化为维护每个点为 \(\max\) 时的 \([L,R]\) 区间。

然后需要写一个支持 【区间+1】、【区间取min】、单点加入、全局查询。

上个吉司机线段树即可。

注意点

  • 吉司机线段树下推 \(fi\) 的标记的时候要注意 \(fi\) 的变化。

    • 错误写法:

      if(fi[rt<<1]>=fi[rt<<1|1])pushcov(rt<<1,tag[rt]);
      if(fi[rt<<1|1]>=fi[rt<<1])pushcov(rt<<1|1,tag[rt]);
      
    • 正确写法:

      int x=fi[rt<<1]-fi[rt<<1|1];
      if(x>=0)pushcov(rt<<1,tag[rt]);
      if(x<=0)pushcov(rt<<1|1,tag[rt]);
      

代码

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=1.5e5+10,M=N<<2,INF=1e9;
int n,a[N],pos[N];
namespace R{
	int fi[M],se[M],cnt[M],siz[M];
	int laz[M],tag[M];
	ll sum[M];
	void pushup(int rt){
		siz[rt]=siz[rt<<1]+siz[rt<<1|1];
		sum[rt]=sum[rt<<1]+sum[rt<<1|1];
		fi[rt]=max(fi[rt<<1],fi[rt<<1|1]);
		se[rt]=max(se[rt<<1],se[rt<<1|1]);
		cnt[rt]=0;
		if(fi[rt<<1]==fi[rt])cnt[rt]+=cnt[rt<<1];
		else se[rt]=max(se[rt],fi[rt<<1]);
		if(fi[rt<<1|1]==fi[rt])cnt[rt]+=cnt[rt<<1|1];
		else se[rt]=max(se[rt],fi[rt<<1|1]);
	}
	void pushadd(int rt,int x){
		if(!siz[rt])return;
		laz[rt]+=x,sum[rt]+=1ll*x*siz[rt],fi[rt]+=x,se[rt]+=x;
	}
	void pushcov(int rt,int x){
		if(!siz[rt])return;
		sum[rt]+=1ll*x*cnt[rt],fi[rt]+=x,tag[rt]+=x;
	}
	void pushdown(int rt){
		if(laz[rt]){
			pushadd(rt<<1,laz[rt]);
			pushadd(rt<<1|1,laz[rt]);
			laz[rt]=0;
		}
		if(tag[rt]){
			int x=fi[rt<<1]-fi[rt<<1|1];
			if(x>=0)pushcov(rt<<1,tag[rt]);
			if(x<=0)pushcov(rt<<1|1,tag[rt]);
			tag[rt]=0;
		}
	}
	void build(int l=1,int r=n,int rt=1){
		laz[rt]=tag[rt]=0;
		if(l==r){
			sum[rt]=0;
			fi[rt]=se[rt]=-INF;
			cnt[rt]=0;
			return;
		}
		int mid=(l+r)>>1;
		build(l,mid,rt<<1);
		build(mid+1,r,rt<<1|1);
		pushup(rt);
	}
	void update(int L,int R,int x,int l=1,int r=n,int rt=1){
		if(L<=l&&r<=R)return pushadd(rt,x);
		int mid=(l+r)>>1;
		pushdown(rt);
		if(L<=mid)update(L,R,x,l,mid,rt<<1);
		if(mid<R)update(L,R,x,mid+1,r,rt<<1|1);
		pushup(rt);
	}
	void modify(int L,int R,int x,int l=1,int r=n,int rt=1){
		if(x>=fi[rt])return;
		if(L<=l&&r<=R&&x>=se[rt])return pushcov(rt,x-fi[rt]);
		int mid=(l+r)>>1;
		pushdown(rt);
		if(L<=mid)modify(L,R,x,l,mid,rt<<1);
		if(mid<R)modify(L,R,x,mid+1,r,rt<<1|1);
		pushup(rt);
	}
	void insert(int x,int y,int l=1,int r=n,int rt=1){
		if(l==r){
			siz[rt]=cnt[rt]=1;
			fi[rt]=sum[rt]=y;
			return;
		}
		int mid=(l+r)>>1;
		pushdown(rt);
		if(x<=mid)insert(x,y,l,mid,rt<<1);
		else insert(x,y,mid+1,r,rt<<1|1);
		pushup(rt);
	}
	ll query(){
		return sum[1];
	}
	int find(int x,int l=1,int r=n,int rt=1){
		if(l==r)return fi[rt];
		int mid=(l+r)>>1;
		pushdown(rt);
		return x<=mid?find(x,l,mid,rt<<1):find(x,mid+1,r,rt<<1|1);
	}
}
namespace L{
	int fi[M],se[M],cnt[M],siz[M];
	int laz[M],tag[M];
	ll sum[M];
	void pushup(int rt){
		siz[rt]=siz[rt<<1]+siz[rt<<1|1];
		sum[rt]=sum[rt<<1]+sum[rt<<1|1];
		fi[rt]=min(fi[rt<<1],fi[rt<<1|1]);
		se[rt]=min(se[rt<<1],se[rt<<1|1]);
		cnt[rt]=0;
		if(fi[rt<<1]==fi[rt])cnt[rt]+=cnt[rt<<1];
		else se[rt]=min(se[rt],fi[rt<<1]);
		if(fi[rt<<1|1]==fi[rt])cnt[rt]+=cnt[rt<<1|1];
		else se[rt]=min(se[rt],fi[rt<<1|1]);
	}
	void pushadd(int rt,int x){
		if(!siz[rt])return;
		laz[rt]+=x,sum[rt]+=1ll*x*siz[rt],fi[rt]+=x,se[rt]+=x;
	}
	void pushcov(int rt,int x){
		if(!siz[rt])return;
		sum[rt]+=1ll*x*cnt[rt],fi[rt]+=x,tag[rt]+=x;
	}
	void pushdown(int rt){
		if(laz[rt]){
			pushadd(rt<<1,laz[rt]);
			pushadd(rt<<1|1,laz[rt]);
			laz[rt]=0;
		}
		if(tag[rt]){
			int x=fi[rt<<1]-fi[rt<<1|1];
			if(x<=0)pushcov(rt<<1,tag[rt]);
			if(x>=0)pushcov(rt<<1|1,tag[rt]);
			tag[rt]=0;
		}
	}
	void build(int l=1,int r=n,int rt=1){
		laz[rt]=tag[rt]=0;
		if(l==r){
			sum[rt]=0;
			fi[rt]=se[rt]=INF;
			cnt[rt]=0;
			return;
		}
		int mid=(l+r)>>1;
		build(l,mid,rt<<1);
		build(mid+1,r,rt<<1|1);
		pushup(rt);
	}
	void update(int L,int R,int x,int l=1,int r=n,int rt=1){
		if(L<=l&&r<=R)return pushadd(rt,x);
		int mid=(l+r)>>1;
		pushdown(rt);
		if(L<=mid)update(L,R,x,l,mid,rt<<1);
		if(mid<R)update(L,R,x,mid+1,r,rt<<1|1);
		pushup(rt);
	}
	void modify(int L,int R,int x,int l=1,int r=n,int rt=1){
		if(x<=fi[rt])return;
		if(L<=l&&r<=R&&x<=se[rt])return pushcov(rt,x-fi[rt]);
		int mid=(l+r)>>1;
		pushdown(rt);
		if(L<=mid)modify(L,R,x,l,mid,rt<<1);
		if(mid<R)modify(L,R,x,mid+1,r,rt<<1|1);
		pushup(rt);
	}
	void insert(int x,int y,int l=1,int r=n,int rt=1){
		if(l==r){
			siz[rt]=cnt[rt]=1;
			fi[rt]=sum[rt]=y;
			return;
		}
		int mid=(l+r)>>1;
		pushdown(rt);
		if(x<=mid)insert(x,y,l,mid,rt<<1);
		else insert(x,y,mid+1,r,rt<<1|1);
		pushup(rt);
	}
	ll query(){
		return sum[1];
	}
	int find(int x,int l=1,int r=n,int rt=1){
		if(l==r)return fi[rt];
		int mid=(l+r)>>1;
		pushdown(rt);
		return x<=mid?find(x,l,mid,rt<<1):find(x,mid+1,r,rt<<1|1);
	}
}
int c[N];
void add(int x,int y){
	for(;x<=n;x+=x&-x)c[x]+=y;
}
void get(int x,int &y){
	for(;x;x^=x&-x)y+=c[x];
}
int main(){
	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]),pos[a[i]]=i;
	L::build(),R::build();
	for(int i=1,x,t;i<=n;i++){
		add(x=pos[i],1),get(x,t=0);
		L::insert(x,1),R::insert(x,i);
		if(x<n){
			R::update(x+1,n,1);
			L::update(x+1,n,1);
			L::modify(x+1,n,t+1);
		}
		if(x>1){
			R::modify(1,x-1,t-1);
		}
//		for(int i=1;i<=n;i++){
//			auto trs=[&](int x){
//				return abs(x)<=n?x:-1;
//			};
//			fprintf(stderr,"(%d,%d)%c",trs(L::find(i)),trs(R::find(i)),"\n "[i<n]);
//		}
		printf("%lld\n",R::query()-L::query()+i);
	}
	return 0;
}