[UOJ164] V 记录历史最值线段树

令标记为<p,c>表示对这个区间加p后和c取max

再多来两个标记记录两次修改间这个节点所能得到的最大标记是多少

诶写线段树之前真应该把标记加法和节点加法先在草稿纸上写好以后再开始敲

不然写起来很难受

#include <iostream>
#include <cstdio>

#define N 500050
#define INF (1LL<<60)

#define mid ((l+r)>>1)
#define ls l,mid,t<<1
#define rs mid+1,r,t<<1^1

using namespace std;
typedef long long LL;
inline int rd() { LL r; scanf("%lld",&r); return r; }
int n,m,ll,rr;
LL x,a[N],b[N],ans_a,ans_b;

struct Tag{ 
	LL p,c,mp,mc; 
	
	Tag operator +=(Tag tmp) {
		Tag ret;	
		ret.p = max(tmp.p+p,-INF);
		ret.c = max(c+tmp.p , tmp.c);
//		r.ex = 1; 
		ret.mp = max(p+tmp.mp , mp);
		ret.mc = max(mc,max(tmp.mc , c+tmp.mp));
		p = ret.p , c = ret.c , mc = ret.mc , mp = ret.mp;
	}
}ag[4*N],now;
const Tag id = (Tag){0,-INF,0,-INF};

void push_down(int t) {
	ag[t<<1] += ag[t];
	ag[t<<1^1] += ag[t];
	ag[t] = id;
}

void build(int l,int r,int t) {
	if (l == r) 
		ag[t] = (Tag){a[l],-INF,a[l],-INF};
	else {
		build(ls); build(rs);
		ag[t] = (Tag){   0,-INF,   0,-INF};
	}
}

void update(int l,int r,int t) {
	if (l > rr || r < ll) return ;
	if (l >= ll && r <= rr) { ag[t] += now; return ; }
	push_down(t); update(ls); update(rs);
}

void query(int l,int r,int t) {
	if (l > x || r < x) return ;
	if (l == r) {
		ans_a = max(ag[t].c , ag[t].p);
		ans_b = max(ag[t].mc, ag[t].mp);
		return ;
	}
	push_down(t); query(ls); query(rs);
}

int main() {
	#ifndef ONLINE_JUDGE
//		freopen("1.in","r",stdin);
//		freopen("1.out","w",stdout);
	#endif 
	n = rd(); m = rd();
	for (int i=1;i<=n;i++) a[i] = b[i] = rd();
	build(1,n,1);
	for (int _=1;_<=m;_++) {
		int cmd = rd();
		if (cmd <= 3)  {
			ll = rd(); rr = rd(); x = rd();	
			if (cmd == 1) now = (Tag){x,-INF,x,-INF};
			if (cmd == 2) now = (Tag){-x,0,-x,0};
			if (cmd == 3) now = (Tag){-INF,x,-INF,x};
			update(1,n,1);
		} else {
			x = rd();
			ans_a = ans_b = 0LL;  
			query(1,n,1);
			if (cmd == 4) 
				printf("%lld\n",ans_a);
			else
				printf("%lld\n",ans_b);
		}
	}
	return 0;
} 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值