codvs4927线段树练习5(set+add) 138 行 简洁

题目链接
与仅有add操作的线段树不同,多了set操作,而set的优先级高于add,set会将以前的add操作所得的价值覆盖掉,而add只会在以前的set基础上继续,故set优先级较高。
既然set优先级高,那么就要区别对待set和add,引入变量ap和sp分别表示add和set的标记,若该节点有sp那么下传时清空子节点的add即可。
代码如下

#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<vector>
#include<algorithm>
#define MAXN 100010
#define LL long long
using namespace std;
const LL INF=9223372036854775806; 
struct Node{
	int l,r,ls,rs; 
	bool sp,ap;
	LL minn,maxn,s,d,st;
};
vector<Node> N;
int n,m;
LL a[MAXN];
void build_tree(int v){
	N[v].ap=N[v].sp=0;
	if(N[v].l==N[v].r){
		N[v].s=N[v].minn=N[v].maxn=a[N[v].l];
		return;
	} 
	int mid=(N[v].l+N[v].r)>>1;
	N.push_back((Node){N[v].l,mid,0,0,INF,-INF});
	N[v].ls=N.size()-1;
	N.push_back((Node){mid+1,N[v].r,0,0,INF,-INF});
	N[v].rs=N.size()-1;
	build_tree(N[v].ls);
	build_tree(N[v].rs);
	N[v].minn=min(N[N[v].ls].minn,N[N[v].rs].minn);
	N[v].maxn=max(N[N[v].ls].maxn,N[N[v].rs].maxn);
	N[v].s=N[N[v].ls].s+N[N[v].rs].s;
}
void push_down(int v){
	if(N[v].sp){
		N[v].s=N[v].st*(LL)(N[v].r-N[v].l+1);
		N[v].maxn=N[v].minn=N[v].st; 
		if(N[v].l<N[v].r){
			N[N[v].ls].st=N[N[v].rs].st=N[v].st;
			N[N[v].ls].sp=N[N[v].rs].sp=1;
			N[N[v].ls].ap=N[N[v].rs].ap=0;
			N[N[v].ls].d=N[N[v].rs].d=0;
		}
		N[v].st=N[v].sp=0;
	}
	if(N[v].ap){
		N[v].s+=N[v].d*(LL)(N[v].r-N[v].l+1);
		N[v].maxn+=N[v].d,N[v].minn+=N[v].d; 
		if(N[v].l<N[v].r){
			N[N[v].ls].d+=N[v].d,N[N[v].rs].d+=N[v].d;
			N[N[v].ls].ap=N[N[v].rs].ap=1;
		} 
		N[v].d=N[v].ap=0;
	}
}
void add(int v,int l,int r,int val){
	push_down(v);
	if(N[v].r<l||N[v].l>r) return;
	else if(N[v].l>=l&&N[v].r<=r){
		N[v].ap=1;
		N[v].d+=val;
		push_down(v);
	}
	else{
		add(N[v].ls,l,r,val);
		add(N[v].rs,l,r,val);
		N[v].s=N[N[v].ls].s+N[N[v].rs].s;
		N[v].maxn=max(N[N[v].ls].maxn,N[N[v].rs].maxn);
		N[v].minn=min(N[N[v].ls].minn,N[N[v].rs].minn);
	}
}
void set(int v,int l,int r,int x){
	push_down(v);
	if(N[v].l>r||N[v].r<l) return;
	else if(N[v].l>=l&&N[v].r<=r){	 
		N[v].st=x;
		N[v].ap=N[v].d=0;
		N[v].sp=1;
		push_down(v);
	}
	else{
		set(N[v].ls,l,r,x);
		set(N[v].rs,l,r,x);
		N[v].s=N[N[v].ls].s+N[N[v].rs].s;
		N[v].maxn=max(N[N[v].ls].maxn,N[N[v].rs].maxn);
		N[v].minn=min(N[N[v].ls].minn,N[N[v].rs].minn);
	}
}
LL sum(int v,int l,int r){
	if(N[v].l>r||N[v].r<l) return 0;
	push_down(v);
	if(N[v].l>=l&&N[v].r<=r) return N[v].s;
	else return sum(N[v].ls,l,r)+sum(N[v].rs,l,r);
}
LL Get_max(int v,int l,int r){
	if(N[v].l>r||N[v].r<l) return -INF;
	push_down(v);
	if(N[v].l>=l&&N[v].r<=r) return N[v].maxn;
	else return max(Get_max(N[v].ls,l,r),Get_max(N[v].rs,l,r));
}
LL Get_min(int v,int l,int r){
	if(N[v].l>r||N[v].r<l) return INF;
	push_down(v);
	if(N[v].l>=l&&N[v].r<=r) return N[v].minn;
	else return min(Get_min(N[v].ls,l,r),Get_min(N[v].rs,l,r));
}
int main(){
	scanf("%d%d",&n,&m);
	N.push_back((Node){1,n,0,0,INF,-INF});
	for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
	build_tree(0); 
	while(m--){
		char Type[5]; scanf("%s",Type);
		if(Type[0]=='a'){
			int a,b,x; scanf("%d%d%d",&a,&b,&x);
			add(0,a,b,x);
		}
		if(Type[0]=='s'&&Type[1]=='e'){
			int a,b,x; scanf("%d%d%d",&a,&b,&x);
			set(0,a,b,x);
		}
		if(Type[0]=='s'&&Type[1]=='u'){
			int a,b; scanf("%d%d",&a,&b);
			printf("%lld\n",sum(0,a,b));
		}
		if(Type[0]=='m'&&Type[1]=='a'){
			int a,b; scanf("%d%d",&a,&b);
			printf("%lld\n",Get_max(0,a,b));
		}
		if(Type[0]=='m'&&Type[1]=='i'){
			int a,b; scanf("%d%d",&a,&b);
			printf("%lld\n",Get_min(0,a,b));
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值