ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF1290E Cartesian Tree

2022-07-10 21:38:41  阅读:187  来源: 互联网

标签:Cartesian 笛卡尔 int sum Tree CF1290E ls 维护 lx


CF1290E Cartesian Tree

题意

\(~~~~\) 给定一个 \(1 \sim n\) 的排列,对于一个整数 \(k\in[1,n]\) ,定义其权值 \(s_k\) 为将排列中 \(\leq k\) 的项的子序列构成大根笛卡尔树后所有节点的子树大小和。\(\forall i\in[1,n]\) 求 \(s_i\).

\(~~~~\) \(1\leq n\leq 1.5\times 10^5\).

题解

\(~~~~\) 作为数据结构确实比较精妙,但实现略恶心。

\(~~~~\) 首先我们发现加入一个新的数后笛卡尔树就很可能会大变样,所以我们不太可能直接维护笛卡尔树。

\(~~~~\) 「你是你 或是妳 都行/会有人 全心的 爱你」既然你不太能上树那就直接放到序列上思考。

\(~~~~\) 关于笛卡尔树的子树大小,我们不难想到就是其所作为最值的最大区间大小,这里由于是大根笛卡尔树所以就是最大的作为最大值的区间大小。所以我们需要维护 \(\sum(r_i-l_i+1)\) ,则对于第 \(i\) 个数加入后,答案为 \(\sum r_i-\sum l_i +k\) 。当然我们也可以维护前后第一个比它大的数的位置,那就是 \(\sum r_i-\sum l_i-k\) 。这里笔者采用了后者。

\(~~~~\) 所以我们来考虑从小到大加入时,加入一个数会有何变化。假设加入的数 \(x\) 在现在的序列中为第 \(p\) 个(这可以用树状数组简单求出),则:

  • 对于在它前面的数,其 \(r\) 会变为 \(\min(r,p)\)

  • 对于在它后面的数,有 \(l\leftarrow l+1,r\leftarrow r+1\),之后其 \(l\) 会变为 \(\max(l,p)\).

  • 对于它本身,其 \(l\) 会变为 \(0\) ,\(r\) 会变为 \(x+1\).

\(~~~~\) 那综上,我们要做的就是:维护区间取最值区间加法单点赋值。直接上吉司机线段树(Segment Beats) 就行了。

\(~~~~\) 但是需要注意的是,我们每次维护的 \(l,r\) 都是在当前序列的意义下的,所以维护和时只能维护存在于当前序列的位置的和。当然这很好解决,打一个 \(Len\) 标记表示可用的位置数即可。至于写两种标记还是数域划分就看个人喜好了。

\(~~~~\) 此外为了防止同时写两种最值操作,不妨把 \(l\) 相关的部分取反维护,这样可以少写一棵线段树。

代码

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int INF=1e9;
struct SegmnetTree{
	#define ls p<<1
	#define rs p<<1|1
	#define lson p<<1,l,mid
	#define rson p<<1|1,mid+1,r
	ll Tag1[600005],Tag2[600005];
	ll Maxn[600005],Maxn2[600005],Cnt[600005],Sum[600005],Len[600005];
	void pushUp(int p)
	{
		Len[p]=Len[ls]+Len[rs]; Maxn[p]=max(Maxn[ls],Maxn[rs]); Sum[p]=Sum[ls]+Sum[rs];
		if(Maxn[ls]==Maxn[rs]) Maxn2[p]=max(Maxn2[ls],Maxn2[rs]),Cnt[p]=Cnt[ls]+Cnt[rs];
		if(Maxn[ls]>Maxn[rs])  Maxn2[p]=max(Maxn2[ls],Maxn[rs]),Cnt[p]=Cnt[ls];
		if(Maxn[ls]<Maxn[rs])  Maxn2[p]=max(Maxn[ls],Maxn2[rs]),Cnt[p]=Cnt[rs];
	}
	void Add(int p,int T1,int T2)
	{
		if(Maxn2[p]==-INF) Maxn[p]+=T1,Sum[p]+=Len[p]*T1;
		else Maxn[p]+=T1,Maxn2[p]+=T2,Sum[p]+=Cnt[p]*T1+(Len[p]-Cnt[p])*T2;
		Tag1[p]+=T1; Tag2[p]+=T2;
	}
	void pushDown(int p)
	{
		int Max=max(Maxn[ls],Maxn[rs]);
		Add(ls,Maxn[ls]==Max?Tag1[p]:Tag2[p],Tag2[p]);
		Add(rs,Maxn[rs]==Max?Tag1[p]:Tag2[p],Tag2[p]);
		Tag1[p]=Tag2[p]=0;
	}
	void Build(int p,int l,int r)
	{
		if(l==r)
		{
			Maxn[p]=Maxn2[p]=-INF; Cnt[p]=Len[p]=Sum[p]=0;
			return;
		}
		int mid=(l+r)>>1;
		Build(lson); Build(rson);
		pushUp(p);
	}
	void Modify(int p,int l,int r,int lx,int rx,int val,int op)
	{
		if(l>r||lx>rx) return;
		if(!Len[p]) return;
		if(op==1&&lx<=l&&r<=rx) {Add(p,val,val);return;}
		if(op==2&&Maxn[p]<=val) return;
		if(op==2&&lx<=l&&r<=rx&&Maxn2[p]<val) {Add(p,val-Maxn[p],0);return;}
		int mid=(l+r)>>1; pushDown(p);
		if(lx<=mid) Modify(lson,lx,rx,val,op);
		if(mid<rx)  Modify(rson,lx,rx,val,op);
		pushUp(p);
	}
	void Give(int p,int l,int r,int aim,int val)
	{
		if(l==r) {Maxn[p]=Sum[p]=val,Maxn2[p]=-INF,Cnt[p]=Len[p]=1;return;}
		int mid=(l+r)>>1; pushDown(p);
		if(aim<=mid) Give(lson,aim,val);
		if(mid<aim)  Give(rson,aim,val);
		pushUp(p);
	}
	ll Query(){return Sum[1];}
	ll DEBUG(int p,int l,int r,int aim)
	{
		if(l==r) return Sum[p];
		int mid=(l+r)>>1;pushDown(p);
		if(aim<=mid) return DEBUG(lson,aim);
		if(mid<aim)  return DEBUG(rson,aim);
	}
	#undef ls
	#undef rs
	#undef lson
	#undef rson
}Seg1,Seg2;
template<typename T>void read(T &x)
{
    T f=1;x=0;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9') {x=x*10+s-'0';s=getchar();}
    x*=f;
}
int n,pos[150005],pos2[150005],Del;
struct BIT{
	int tr[150005];
	inline int lowbit(int x){return x&(-x);}
	void Add(int x,int val){for(;x<=n;x+=lowbit(x)) tr[x]+=val;}
	int Query(int x){int ret=0;for(;x;x-=lowbit(x)) ret+=tr[x];return ret;}
}BIT;
int main() {
	read(n);
	for(int i=1,x;i<=n;i++) read(x),pos[x]=i,pos2[x]=BIT.Query(x)+1,BIT.Add(x,1);//pos2 表示最开始插入在第几个 
	Seg1.Build(1,1,n); Seg2.Build(1,1,n);
	for(int i=1;i<=n;i++)
	{
		Seg1.Give(1,1,n,pos[i],0); Seg2.Give(1,1,n,pos[i],i+1);
		Seg1.Modify(1,1,n,pos[i]+1,n,-1,1); Seg2.Modify(1,1,n,pos[i]+1,n,1,1);
		Seg1.Modify(1,1,n,pos[i]+1,n,-pos2[i],2); Seg2.Modify(1,1,n,1,pos[i]-1,pos2[i],2);
		printf("%lld\n",Seg2.Query()+Seg1.Query()-i);
//		for(int j=1;j<=n;j++) printf("(%d %d)",-Seg1.DEBUG(1,1,n,j),Seg2.DEBUG(1,1,n,j));puts("");
	}
	return 0;
}

标签:Cartesian,笛卡尔,int,sum,Tree,CF1290E,ls,维护,lx
来源: https://www.cnblogs.com/Azazel/p/16464088.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有