[复习]线段树基础
大部分题目是纯模板,只写一下《山海经》
题意:查询区间最大字段和(不带修)
考虑区间最大子段和由哪里贡献得到,
可能是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;
}