大江东去,浪淘尽,千古风流人物。故垒西边,人道是,三国周郎赤壁。乱石穿空,惊涛拍岸,卷起千堆雪。江山如画,一时多少豪杰。遥想公瑾当年,小乔初嫁了,雄姿英发。羽扇纶巾,谈笑间,樯橹灰飞烟灭。故国神游,多情应笑我,早生华发。人生如梦,一尊还酹江月。

【模板】吉司机线段树(势能线段树)

吉司机最经典的应用,区间最值更新

HDU 5306

其中对最大值和次大值及其个数的维护方式值得学习

#include<bits/stdc++.h>
using namespace std;

#define go(i,a,b) for(int i=a;i<=b;++i)
#define com(i,a,b) for(int i=a;i>=b;--i)
#define mem(a,b) memset(a,b,sizeof(a))
#define int long long

const int N=1000000+10;

int n,m,a[N];
struct tree{//其实更新标记和最大值可以二合一
//若更新成功则最大值就是标记,若没有更新下传最大值也不会更新子区间 
	int l,r,mx,se,c,sum;
	#define l(i) t[i].l
	#define r(i) t[i].r
	#define c(i) t[i].c
	#define mx(i) t[i].mx
	#define se(i) t[i].se
	#define sum(i) t[i].sum
	#define ls rt<<1
	#define rs rt<<1|1
}t[N<<2];

template<typename T>void read(T &x){
	x=0;char c=getchar(),f=1;
	while(!isdigit(c)){ if(c=='-') f=-1; c=getchar(); }
	while(isdigit(c)){ x=x*10+c-'0'; c=getchar(); }
	x*=f;
}

void push_up(int rt){
	sum(rt)=sum(ls)+sum(rs);
	mx(rt)=max(mx(ls),mx(rs));
	se(rt)=max(se(ls),se(rs));
	c(rt)=0;
	if(mx(ls)!=mx(rs)) se(rt)=max(se(rt),min(mx(ls),mx(rs)));
	if(mx(rt)==mx(ls)) c(rt)+=c(ls);
	if(mx(rt)==mx(rs)) c(rt)+=c(rs);
}

void update(int rt,int z){//在下传标记时z不可能<=se(rt),因为Z>se(rt的祖先节点)>=se(rt)
	if(z>=mx(rt)) return;
	sum(rt)-=(mx(rt)-z)*c(rt);
	mx(rt)=z;
}

void build(int rt,int l,int r){
	l(rt)=l,r(rt)=r;
	if(l==r){
		mx(rt)=sum(rt)=a[l],se(rt)=-1;
		c(rt)=1;
		return;
	}
	int mid=l+r>>1;
	build(ls,l,mid);
	build(rs,mid+1,r);
	push_up(rt);
}

void push_down(int rt){
	update(ls,mx(rt)),update(rs,mx(rt));
}

void change(int rt,int x,int y,int z){
	if(z>=mx(rt)) return;//剪枝,如果比大区间的最大值还大,自然不可能修改小区间 
	if(l(rt)>=x&&r(rt)<=y&&z>se(rt)){
		update(rt,z);
		return;
	}
	int mid=l(rt)+r(rt)>>1;
	push_down(rt);
	if(x<=mid) change(ls,x,y,z);
	if(y>mid) change(rs,x,y,z);
	push_up(rt);
}

int getmax(int rt,int x,int y){
	if(l(rt)>=x&&r(rt)<=y) return mx(rt);
	push_down(rt);
	int ans=0;
	int mid=l(rt)+r(rt)>>1;
	if(x<=mid) ans=max(ans,getmax(ls,x,y));
	if(y>mid) ans=max(ans,getmax(rs,x,y));
	return ans;
}

int getsum(int rt,int x,int y){
	if(l(rt)>=x&&r(rt)<=y) return sum(rt);
	push_down(rt);
	int ans=0,mid=l(rt)+r(rt)>>1;
	if(x<=mid) ans+=getsum(ls,x,y);
	if(y>mid) ans+=getsum(rs,x,y);
	return ans;
}

void work(){
	read(n),read(m);
	go(i,1,n) read(a[i]);
	build(1,1,n);
	int op,x,y,z;
	while(m--){
		read(op),read(x),read(y);
		if(!op) read(z),change(1,x,y,z);
		else if(op==1) printf("%lld\n",getmax(1,x,y));
		else if(op==2) printf("%lld\n",getsum(1,x,y));
	}
}

signed main(){
	//freopen("input.txt","r",stdin);
	int T;read(T);
	while(T--) work();
	return 0;
}
posted @ 2019-09-27 17:21  White_star  阅读(607)  评论(0编辑  收藏  举报
}