线段树历史值

发布时间 2023-11-09 09:43:42作者: SError

P6242 【模板】线段树 3

支持区间加,区间取 \(\min\),区间求和,区间 \(\max\),区间历史 \(\max\)

先提一嘴吉司机。

就是对线段树的每个节点记录最大值,严格次大值和最大值个数,只在 \(se<v<mx\) 的区间操作,否则向下递归。如果没有区间加,复杂度势能分析是 \(O((n+m)\log n)\) 的,否则为 \(O(m\log^2 n)\)

考虑 \(\operatorname{pushdown}\) 需要的 \(\mathrm{tag}\)

  • \(\mathrm{tag1}\):区间 \(\max\) 的懒标记。

  • \(\mathrm{tag2}\):区间非 \(\max\) 的懒标记。

  • \(\mathrm{tag3}\):区间 \(\max\) 的懒标记的最大值。

  • \(\mathrm{tag4}\):区间非 \(\max\) 的懒标记的最大值。

注意要先更新历史值再更新当前值。

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define N 500010
#define inf 2e9
using namespace std;
int read(){
	int x=0,w=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
	while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return x*w;
}
#define sum(x) tr[x].sum
#define len(x) tr[x].len
#define ma(x) tr[x].ma
#define cnt(x) tr[x].cnt
#define se(x) tr[x].se
#define mb(x) tr[x].mb
#define add1(x) tr[x].add1
#define add2(x) tr[x].add2
#define add3(x) tr[x].add3
#define add4(x) tr[x].add4
struct Tree{
	ll sum;int len;
	int ma,cnt,se,mb;
	int add1,add2,add3,add4;
}tr[N<<2];
#define ls p<<1
#define rs p<<1|1
void pushup(int p){
	sum(p)=sum(ls)+sum(rs);
	ma(p)=max(ma(ls),ma(rs)),mb(p)=max(mb(ls),mb(rs));
	if(ma(ls)==ma(rs))
		se(p)=max(se(ls),se(rs)),cnt(p)=cnt(ls)+cnt(rs);
	else if(ma(ls)>ma(rs))
		se(p)=max(se(ls),ma(rs)),cnt(p)=cnt(ls);
	else
		se(p)=max(ma(ls),se(rs)),cnt(p)=cnt(rs);
}
void change(int p,int k1,int k2,int k3,int k4){
	sum(p)+=1ll*k1*cnt(p)+1ll*k2*(len(p)-cnt(p));
	mb(p)=max(mb(p),ma(p)+k3),ma(p)+=k1;
	if(se(p)!=-inf)se(p)+=k2;
	add3(p)=max(add3(p),add1(p)+k3);
	add4(p)=max(add4(p),add2(p)+k4);
	add1(p)+=k1,add2(p)+=k2;
}
void pushdown(int p){
	int mx=max(ma(ls),ma(rs));
	if(ma(ls)==mx)
		change(ls,add1(p),add2(p),add3(p),add4(p));
	else change(ls,add2(p),add2(p),add4(p),add4(p));
	if(ma(rs)==mx)
		change(rs,add1(p),add2(p),add3(p),add4(p));
	else change(rs,add2(p),add2(p),add4(p),add4(p));
	add1(p)=add2(p)=add3(p)=add4(p)=0;
}
void build(int p,int l,int r){
	len(p)=r-l+1;
	if(l==r){
		sum(p)=ma(p)=mb(p)=read();
		cnt(p)=1,se(p)=-inf;
		return;
	}
	int mid=(l+r)>>1;
	build(ls,l,mid),build(rs,mid+1,r);
	pushup(p);
}
ll qsum(int p,int l,int r,int L,int R){
	if(L<=l&&r<=R)return sum(p);
	int mid=(l+r)>>1;pushdown(p);
	ll ret=0;
	if(L<=mid)ret+=qsum(ls,l,mid,L,R);
	if(R>mid)ret+=qsum(rs,mid+1,r,L,R);
	return ret;
}
int qma(int p,int l,int r,int L,int R){
	if(L<=l&&r<=R)return ma(p);
	int mid=(l+r)>>1;pushdown(p);
	if(R<=mid)return qma(ls,l,mid,L,R);
	if(L>mid)return qma(rs,mid+1,r,L,R);
	return max(qma(ls,l,mid,L,R),qma(rs,mid+1,r,L,R));
}
int qmb(int p,int l,int r,int L,int R){
	if(L<=l&&r<=R)return mb(p);
	int mid=(l+r)>>1;pushdown(p);
	if(R<=mid)return qmb(ls,l,mid,L,R);
	if(L>mid)return qmb(rs,mid+1,r,L,R);
	return max(qmb(ls,l,mid,L,R),qmb(rs,mid+1,r,L,R));
}
void uadd(int p,int l,int r,int L,int R,int k){
	if(L<=l&&r<=R){
		sum(p)+=1ll*k*len(p);
		ma(p)+=k,mb(p)=max(mb(p),ma(p));
		if(se(p)!=-inf)se(p)+=k;
		add1(p)+=k,add2(p)+=k;
		add3(p)=max(add3(p),add1(p)),add4(p)=max(add4(p),add2(p));
		return;
	}
	int mid=(l+r)>>1;pushdown(p);
	if(L<=mid)uadd(ls,l,mid,L,R,k);
	if(R>mid)uadd(rs,mid+1,r,L,R,k);
	pushup(p);
}
void umin(int p,int l,int r,int L,int R,int v){
	if(L>r||R<l||v>=ma(p))return;
	if(L<=l&&r<=R&&se(p)<v){
		int k=ma(p)-v;
		sum(p)-=1ll*cnt(p)*k;
		ma(p)=v,add1(p)-=k;
		return;
	}
	int mid=(l+r)>>1;pushdown(p);
	umin(ls,l,mid,L,R,v);
	umin(rs,mid+1,r,L,R,v);
	pushup(p);
}
int n,m;
int main(){
	n=read(),m=read();
	build(1,1,n);
	for(int opt,l,r;m;m--){
		opt=read(),l=read(),r=read();
		if(opt==1)uadd(1,1,n,l,r,read());
		if(opt==2)umin(1,1,n,l,r,read());
		if(opt==3)printf("%lld\n",qsum(1,1,n,l,r));
		if(opt==4)printf("%d\n",qma(1,1,n,l,r));
		if(opt==5)printf("%d\n",qmb(1,1,n,l,r));
	}
	
	return 0;
}