吉司机线段树求调,玄关
查看原帖
吉司机线段树求调,玄关
1163927
F1NE楼主2024/10/16 22:16

rt,虽然define写得多但是都能看懂

#include<bits/stdc++.h>
#define now sgt[p]
#define ls sgt[p<<1]
#define _ls p<<1
#define rs sgt[p<<1|1]
#define _rs p<<1|1
#define getm int m=(now.s+now.t)>>1
typedef long long ll;
using namespace std;
const int maxi=5e5+9;
int N,M,a[maxi],l,r,k,v;
struct node{
	ll sum;
	int s,t,mxa,cnt,sec,mxb;
	int lz1,//LaZy tag of Maximun
		lz2,//LaZy tag of Else
		lz3,//Maximum of lz1 
		lz4;//Maximum of lz2
}sgt[maxi<<2];
inline int max(int a,int b){return a>b?a:b;}
inline void output(int p){
cerr<<"p="<<p
	<<",sum="<<now.sum
	<<",s="<<now.s
	<<",t="<<now.t
	<<",mxa="<<now.mxa
	<<",cnt="<<now.cnt
	<<",sec="<<now.sec
	<<",mxb="<<now.mxb
	<<",lz1="<<now.lz1
	<<",lz2="<<now.lz2
	<<",lz3="<<now.lz3
	<<",lz4="<<now.lz4<<'\n';
}
void debug(int p){
	output(p);
	if(now.s==now.t)return;
	debug(_ls),debug(_rs);
}
inline void update(int p){
	now.sum=ls.sum+rs.sum;
	//上传区间和 
	now.mxa=max(ls.mxa,rs.mxa);
	now.mxb=max(ls.mxb,rs.mxb);
	//上传区间最大值以及区间历史最大值 
	if(ls.mxa==rs.mxa){
		now.sec=max(ls.sec,rs.sec);
		now.cnt=ls.cnt+rs.cnt;
	}else if(ls.mxa>rs.mxa){
		now.sec=max(ls.sec,rs.mxa);
		now.cnt=ls.cnt;
	}else{
		now.sec=max(ls.mxa,rs.sec);
		now.cnt=rs.cnt;
	}
	//分类讨论以计算sec和cnt 
	return;
}
inline void push(int k1,int k2,int k3,int k4,int p){
	//传下来的变量分别是分别对应四个lazy_tag 
	now.sum+=1ll*k1*now.cnt+1ll*k2*(now.t-now.s+1-now.cnt);
	//区间+=区间最大值改变量+区间非最大值改变量
	now.mxb=max(now.mxb,now.mxa+k3);
	//用 更新前最大值+最大增加量 更新 历史最大值 
	now.mxa+=k1;
	//mxb更新完再更新mxa 
	if(now.sec!=-INT_MAX)now.sec+=k2;
	//若有次大值则用非最大值改变量更新 
	now.lz3=max(now.lz3,now.lz1+k3);
	now.lz4=max(now.lz4,now.lz2+k4);
	//用 更新前的改变量+最大增加量 更新lz3和lz4 
	now.lz1+=k1,now.lz2+=k2;
	//更新 最大值和次大值的改变量 
	return;
}
inline void pushdown(int p){
	int mxn=max(ls.mxa,rs.mxa);
	if(ls.mxa==mxn){
		push(now.lz1,now.lz2,now.lz3,now.lz4,_ls);
	}else{
		push(now.lz2,now.lz2,now.lz4,now.lz4,_ls);
	}
	if(rs.mxa==mxn){
		push(now.lz1,now.lz2,now.lz3,now.lz4,_ls);
	}else{
		push(now.lz2,now.lz2,now.lz4,now.lz4,_ls);
	}
	//若子区间有最大值则用lz1和lz3更新,无则不用 
	now.lz1=now.lz2=now.lz3=now.lz4=0;
	//更新完清零哈 
	return;
}
void build(int s,int t,int p){
	now.s=s,now.t=t;
	if(s==t){
		now.cnt=1;
		now.sum=now.mxa=now.mxb=0ll+a[s];
		now.sec=-INT_MAX;
		//因为区间可能无次大值故赋极小值 
		return;
	}
	int m=(s+t)>>1;
	build(s,m,_ls);
	build(m+1,t,_rs);
	update(p);
	return;
}
void _1/*区间加*/(int p){
cerr<<"_1:"<<p<<'\n';
	if(l<=now.s&&now.t<=r){
		now.sum+=1ll*k*(now.t-now.s+1);
		now.mxa+=k;
		now.mxb=max(now.mxa,now.mxb);
		if(now.sec!=-INT_MAX)now.sec+=k;
		now.lz1+=k,now.lz2+=k;
		now.lz3=max(now.lz1,now.lz3);
		now.lz4=max(now.lz2,now.lz4);
		return; 
	}
	pushdown(p);
	getm;
	if(l<=m)_1(_ls);
	if(m<r)_1(_rs);
	return;
} 
void _2/*区间取min*/(int p){
	if(v>=now.mxa)return; 
cerr<<"_2:"<<p<<'\n';
	if(l<=now.s
	 &&now.t<=r
	 &&now.sec<v){//不能取等,否则无法更新次大值
		int dlt=now.mxa-v;
		now.sum-=1ll*now.cnt*dlt;
		now.mxa=v,now.lz1-=dlt;
		return; 
	}
	pushdown(p);getm;
	if(l<=m)_1(_ls);
	if(m<r)_1(_rs);
	update(p);
	return;
} 
ll _3/*区间和*/(int p){
cerr<<"_3:"<<p<<'\n';
output(p);
	if(l<=now.s&&now.t<=r)return now.sum;
cerr<<"lol\n";
	pushdown(p);
cerr<<"pushed down\n";
	ll ans=0;getm;
cerr<<"m="<<m<<'\n';
	if(l<=m){
		ans+=_3(_ls);
cerr<<"ls searched\n";
	}
	if(m<r){
		ans+=_3(_rs);
cerr<<"rs searched\n";
	}
cerr<<"ans="<<ans<<'\n';
	update(p);
cerr<<"updated\n";
	return ans;
}
int _4/*区间最大值*/(int p){
cerr<<"_4:"<<p<<'\n'; 
	if(l<=now.s&&now.t<=r)return now.mxa;
	pushdown(p);
	int ans=-INT_MAX;getm;
	if(l<=m)ans=max(ans,_4(_ls));
	if(m<r)ans=max(ans,_4(_rs));
	update(p);
	return ans;
}
int _5/*区间历史最大值*/(int p){
cerr<<"_5:"<<p<<'\n';
	if(l<=now.s&&now.t<=r)return now.mxb;
	pushdown(p);
	int ans=-INT_MAX;getm;
	if(l<=m)ans=max(ans,_5(_ls));
	if(m<r)ans=max(ans,_5(_rs));
	update(p);
	return ans;
} 
int main(){
	cin>>N>>M;
	for(int i=1;i<=N;i++)scanf("%d",&a[i]);
	build(1,N,1);
debug(1);
	for(int i=1,op,r,k,v;i<=M;i++){
		scanf("%d%d%d",&op,&l,&r);
cerr<<"l="<<l<<",r="<<r<<'\n';
		if(op==1){
			scanf("%d",&k);_1(1);
		}
		if(op==2){
			scanf("%d",&v);_2(1);
		}
		if(op==3)printf("%lld\n",_3(1));
		if(op==4)printf("%d\n",_4(1));
		if(op==5)printf("%d\n",_5(1));
	}
	return 0;
}
2024/10/16 22:16
加载中...