[复习]线段树基础

大部分题目是纯模板,只写一下《山海经》
题意:查询区间最大字段和(不带修)
考虑区间最大子段和由哪里贡献得到,
可能是lson的ans,rson的ans,也可以是lson与rson拼接而成
只需要抽象出加法(push_up)操作,就很好理解了
网上题解太麻烦, 需要各种分类讨论,容易写挂
所以直接抽象出加法即可
维护4个range:左侧最大和lm、右侧最大和rm、总和sum、最大子段和ans
\(ans = max(lm+rm, l.ans, r.ans)\)
然后套路维护剩下的\(lm rm sum\)即可
需要注意的几个地方:区间为空时候要特判一下即可
即:区间为空的时候区间加法的l,r会挂掉,然后区间加之前需要判断是否为空区间

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cassert>
const int N = 1e5+10, TR = 4*N;
int a[N];
int n, q;
struct rg_t{
	int val, l, r;
	rg_t(){r = -1;val = 0, l = 1;}
	rg_t(int val_, int l_, int r_):val(val_), l(l_), r(r_){}
	friend bool operator <(const rg_t& x, const rg_t& y){
		if(y.empty()) return false;
		if(x.empty()) return true;
		if(x.val != y.val) return x.val < y.val;
		if(x.l != y.l) return x.l>y.l;
		return x.r > y.r;
	}
	bool empty()const{
		return r==-1;
	}
	void make_empty(){
		r = -1;
	}
	friend rg_t operator +(const rg_t& x, const rg_t& y){
		if(y.empty()) return x;
		if(x.empty()) return y;
		return rg_t(x.val+y.val, x.l, y.r);
	}
};
struct segment_tree{
	struct node{
		rg_t ans, lm, rm, sum;
		//sum:总和 
		node(){}
		node(int val, int u){
			ans = sum = rg_t(val, u, u);
			if(val > 0) lm = rm = sum;
		}
		node(rg_t ans_, rg_t lm_, rg_t rm_, rg_t sum_):ans(ans_), lm(lm_), rm(rm_),sum(sum_) {}
		bool empty(){
			return sum.empty();
		}
		friend node operator +(const node& a, const node& b){
			if(b.empty()) return a;
			if(a.empty()) return b;
			node c; 
			c.ans = std::max(std::max(a.ans, b.ans), a.rm+b.lm);
			c.sum = a.sum+b.sum;
			rg_t tlm, trm;
			tlm = a.sum+b.lm, trm = a.rm+b.sum;
			if(b.lm.empty()) tlm = a.sum, tlm.r = b.sum.r;
			if(a.rm.empty()) trm = b.sum, tlm.l = a.sum.l;
			c.lm = std::max(a.lm, tlm);
			c.rm = std::max(b.rm, trm);
			return c;
		}
	}tree[TR];
	void update(int rt, int val, int l){
		tree[rt] = node(val, l);
	}
	void push_up(int rt){ 
		tree[rt] = tree[rt<<1]+tree[rt<<1|1];
	}
	void build(int rt, int l, int r){
		if(l == r) return update(rt, a[l], l);
		int mid = (l+r)>>1;
		build(rt<<1, l, mid);
		build(rt<<1|1, mid+1, r);
		push_up(rt);
	}
	node query(int rt, int l, int r, int s, int t){ 
		if(s <= l && r <= t) return tree[rt];
		int mid = (l+r)>>1;
		node a,b;
		if(s <= mid)a = query(rt<<1, l, mid, s, t);
		if(t > mid) b = query(rt<<1|1, mid+1, r, s, t);
		return a+b;
	}
}segt;
int main(){
	scanf("%d%d", &n, &q);
	for(int i = 1; i <= n; ++i){
		scanf("%d", a+i);
	}
	segt.build(1 ,1, n);
	for(int i = 1; i <= q; ++i){
		int l, r; scanf("%d%d", &l, &r);
		rg_t ans = segt.query(1, 1, n, l ,r).ans;
		printf("%d %d %d\n", ans.l, ans.r, ans.val);
	}
	return 0;
}
posted @ 2022-01-20 14:56  CDsidi  阅读(38)  评论(0编辑  收藏  举报