线段树维护区间最值操作与区间历史最值

宏定义

  • #define pl p<<1\texttt{\#define pl p<<1}:节点 pp 的左儿子。
  • #define pr p<<1|1\texttt{\#define pr p<<1|1}:节点 pp 的右儿子。

常量与变量

  • long long inf\texttt{long long inf}:一个极大值。
  • Tree a[i]\texttt{Tree a[i]}:节点 ii 的信息。
  • long long a[i].mxa\texttt{long long a[i].mxa}:此时节点 ii 管理的区间的最大值。
  • long long a[i].cnt\texttt{long long a[i].cnt}:此时节点 ii 管理的区间的最大值的个数。
  • long long a[i].mxb\texttt{long long a[i].mxb}:节点 ii 管理的区间的历史最大值。
  • long long a[i].se\texttt{long long a[i].se}:此时节点 ii 管理的区间的严格次大值。
  • long long a[i].sum\texttt{long long a[i].sum}:此时节点 ii 管理的区间的数的和。
  • long long a[i].mxtag1\texttt{long long a[i].mxtag1}:此时节点 ii 管理的区间的最大值的增加标记。
  • long long a[i].setag1\texttt{long long a[i].setag1}:此时节点 ii 管理的区间的非最大值的增加标记。
  • long long a[i].mxtag2\texttt{long long a[i].mxtag2}:节点 ii 管理的区间的最大值的历史最大增加标记。
  • long long a[i].setag2\texttt{long long a[i].setag2}:节点 ii 管理的区间的非最大值的历史最大增加标记。

函数

  • void pushup(int p)\texttt{void pushup(int p)}:将节点 pp 的孩子的信息上传。
  • void update(int p,int L,int R,long long t1,long long st1,long long t2,long long st2)\texttt{void update(int p,int L,int R,long long t1,long long st1,long long t2,long long st2)}:将信息 (t1,st1,t2,st2)(t1,st1,t2,st2) 下传到掌管区间为 [L,R][L,R] 的节点 pp
  • void pushdown(int p,int L,int R)\texttt{void pushdown(int p,int L,int R)}:将掌管区间为 [L,R][L,R] 的节点 pp 的信息下传到孩子。
  • void build(int p,int L,int R)\texttt{void build(int p,int L,int R)}:建树 pp,掌管区间为 [L,R][L,R]
  • void add(int p,int L,int R,int l,int r,long long v)\texttt{void add(int p,int L,int R,int l,int r,long long v)}:将掌管区间为 [L,R][L,R] 的节点 pp 中下标 [l,r][l,r] 的数都加上 vv
  • void domin(int p,int L,int R,int l,int r,long long v)\texttt{void domin(int p,int L,int R,int l,int r,long long v)}:将掌管区间为 [L,R][L,R] 的节点 pp 中下标 [l,r][l,r] 的数都对 vvmin\min
  • long long asksum(int p,int L,int R,int l,int r)\texttt{long long asksum(int p,int L,int R,int l,int r)}:求掌管区间为 [L,R][L,R] 的节点 pp 中下标 [l,r][l,r] 的数的和。
  • long long askmxa(int p,int L,int R,int l,int r)\texttt{long long askmxa(int p,int L,int R,int l,int r)}:求掌管区间为 [L,R][L,R] 的节点 pp 中下标 [l,r][l,r] 的数的最大值。
  • long long askmxb(int p,int L,int R,int l,int r)\texttt{long long askmxb(int p,int L,int R,int l,int r)}:求掌管区间为 [L,R][L,R] 的节点 pp 中下标 [l,r][l,r] 的数的历史最大值。

代码

#define pl p<<1
#define pr p<<1|1
struct Segment_Tree{
	long long inf=2e9;
	struct Tree{
		long long mxa,cnt,mxb,se,sum;
		long long mxtag1,setag1,mxtag2,setag2;
	}a[N<<2];
	void pushup(int p){
		a[p].sum=a[pl].sum+a[pr].sum;
		a[p].mxa=max(a[pl].mxa,a[pr].mxa);
		a[p].mxb=max(a[pl].mxb,a[pr].mxb);
		if(a[pl].mxa==a[pr].mxa){
			a[p].se=max(a[pl].se,a[pr].se);
			a[p].cnt=a[pl].cnt+a[pr].cnt;
		}
		else if(a[pl].mxa>a[pr].mxa){
			a[p].se=max(a[pl].se,a[pr].mxa);
			a[p].cnt=a[pl].cnt;
		}
		else{
			a[p].se=max(a[pl].mxa,a[pr].se);
			a[p].cnt=a[pr].cnt;
		}
	}
	void update(int p,int L,int R,long long t1,long long st1,long long t2,long long st2){
		a[p].sum+=t1*a[p].cnt+st1*(R-L+1-a[p].cnt);
		a[p].mxb=max(a[p].mxb,a[p].mxa+t2);
		a[p].mxtag2=max(a[p].mxtag2,a[p].mxtag1+t2);
		a[p].setag2=max(a[p].setag2,a[p].setag1+st2);
		a[p].mxa+=t1;
		a[p].mxtag1+=t1;
		a[p].setag1+=st1;
		if(a[p].se!=-inf)
			a[p].se+=st1;
	}
	void pushdown(int p,int L,int R){
		ll mx=max(a[pl].mxa,a[pr].mxa);
		int mid=(L+R)>>1;
		if(a[pl].mxa==mx)
			update(pl,L,mid,a[p].mxtag1,a[p].setag1,a[p].mxtag2,a[p].setag2);
		else
			update(pl,L,mid,a[p].setag1,a[p].setag1,a[p].setag2,a[p].setag2);
		if(a[pr].mxa==mx)
			update(pr,mid+1,R,a[p].mxtag1,a[p].setag1,a[p].mxtag2,a[p].setag2);
		else
			update(pr,mid+1,R,a[p].setag1,a[p].setag1,a[p].setag2,a[p].setag2);
		a[p].mxtag1=a[p].setag1=a[p].mxtag2=a[p].setag2=0;
	}
	void build(int p,int L,int R){
		if(L==R){
			a[p].sum=a[p].mxa=a[p].mxb=b[L];
			a[p].cnt=1;
			a[p].se=-inf;
			return;
		}
		int mid=(L+R)>>1;
		build(pl,L,mid);
		build(pr,mid+1,R);
		pushup(p);
	}
	void add(int p,int L,int R,int l,int r,long long v){
		if(l<=L&&R<=r){
			update(p,L,R,v,v,v,v);
			return;
		}
		pushdown(p,L,R);
		int mid=(L+R)>>1;
		if(l<=mid)
			add(pl,L,mid,l,r,v);
		if(r>mid)
			add(pr,mid+1,R,l,r,v);
		pushup(p);
	}
	void domin(int p,int L,int R,int l,int r,long long v){
		if(v>=a[p].mxa)
			return;
		if(l<=L&&R<=r&&v>a[p].se){
			update(p,L,R,v-a[p].mxa,0,v-a[p].mxa,0);
			return;
		}
		pushdown(p,L,R);
		int mid=(L+R)>>1;
		if(l<=mid)
			domin(pl,L,mid,l,r,v);
		if(r>mid)
			domin(pr,mid+1,R,l,r,v);
		pushup(p);
	}
	long long asksum(int p,int L,int R,int l,int r){
		if(l<=L&&R<=r)
			return a[p].sum;
		pushdown(p,L,R);
		int mid=(L+R)>>1;
		ll ans=0;
		if(l<=mid)
			ans+=asksum(pl,L,mid,l,r);
		if(r>mid)
			ans+=asksum(pr,mid+1,R,l,r);
		return ans;
	}
	long long askmxa(int p,int L,int R,int l,int r){
		if(l<=L&&R<=r)
			return a[p].mxa;
		pushdown(p,L,R);
		int mid=(L+R)>>1;
		ll ans=-inf;
		if(l<=mid)
			ans=max(ans,askmxa(pl,L,mid,l,r));
		if(r>mid)
			ans=max(ans,askmxa(pr,mid+1,R,l,r));
		return ans;
	}
	long long askmxb(int p,int L,int R,int l,int r){
		if(l<=L&&R<=r)
			return a[p].mxb;
		pushdown(p,L,R);
		int mid=(L+R)>>1;
		ll ans=-inf;
		if(l<=mid)
			ans=max(ans,askmxb(pl,L,mid,l,r));
		if(r>mid)
			ans=max(ans,askmxb(pr,mid+1,R,l,r));
		return ans;
	}
}tree;
posted @ 2022-05-28 20:01  luckydrawbox  阅读(16)  评论(0)    收藏  举报  来源