#线段树
想了想还是给题面:
You are given a sequence \(A[1], A[2], \cdots, A[N] . ( |A[i]| \le 15007 , 1 \le N \le 50000 )\). A query is defined as follows:
- \(\verb|Query(x,y) = Max { a[i]+a[i+1]+...+a[j]; x ≤ i ≤ j ≤ y }.|\)
Given \(M\) queries, your program must output the results of these queries.
其实就是维护一个区间中的最长子段和。我们可以考虑维护一个区间,分别维护4个attribute:
sum
;代表区间和pre
;代表区间最大前缀和suf
;代表区间最大后缀和sub
;代表区间最大子段和考虑以下情况,父区间为\(Tr\),其两个子区间分别为\(Tr_l, Tr_r\)。我们分别讨论如何维护每个attribute:
sum
, 直接维护即可:Tr.sum = Trl.sum + Trr.sum
sub
,有三种情况,分别是\(Tr_l\)单独贡献, \(Tr_r\)单独贡献以及\(Tr_l\)贡献后缀,\(Tr_r\)贡献前缀,所以维护方式为: Tr.sub = max(Trl.sub, Trr.sub, Trl.suf + Trr.pre)
pre
,有两种情况,分别是\(Tr_l\)单独贡献前缀,\(Tr_l\)贡献整个区间以及\(Tr_r\)贡献前缀,所以维护方式:Tr.pre = max(Trl.pre, Trl.sum + Trr.pre)
suf
同理,Tr.suf = max(Trr.suf, Trr.sum + Trl.suf)
在确定如何维护区间更新之后直接写线段树即可:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e4 + 50;
#define lc(x) (x<<1)
#define rc(x) (x<<1|1)
int f[maxn];
struct Tr{
int l, r, pre, suf, sub, sum;
Tr () {}
Tr (int _l, int _r, int v): l(_l), r(_r), sum(v){
pre = suf = sub = sum;
}
} tr[maxn << 2];
void pushup(int node){
tr[node].sum = tr[lc(node)].sum + tr[rc(node)].sum;
tr[node].sub = std::max({tr[lc(node)].sub, tr[rc(node)].sub, tr[lc(node)].suf + tr[rc(node)].pre});
tr[node].pre = std::max(tr[lc(node)].pre, tr[lc(node)].sum + tr[rc(node)].pre);
tr[node].suf = std::max(tr[rc(node)].suf, tr[rc(node)].sum + tr[lc(node)].suf);
}
void build_tree(int node, int start, int end){
if (start == end) return tr[node] = Tr(start, end, f[start]), void();
int mid = start + end >> 1;
int left_node = lc(node);
int right_node = rc(node);
build_tree(left_node , start, mid);
build_tree(right_node, mid+1, end);
pushup(node);
}
Tr _query(int node, int start, int end, int L, int R){
if (L <= start && end <= R) return tr[node];
int mid = start + end >> 1;
if (mid < L) return _query(rc(node), mid+1, end, L, R);
if (mid >= R) return _query(lc(node), start, mid, L, R);
Tr subl = _query(lc(node), start, mid, L, R);
Tr subr = _query(rc(node), mid+1, end, L, R);
Tr ret;
ret.sum = subl.sum + subr.sum;
ret.sub = std::max({subl.sub, subr.sub, subl.suf + subr.pre});
ret.pre = std::max(subl.pre, subl.sum + subr.pre);
ret.suf = std::max(subr.suf, subr.sum + subl.suf);
return ret;
}
int query(int node, int start, int end, int L, int R){
Tr ans = _query(node, start, end, L, R);
return ans.sub;
}
const int rt = 1; // start from 1
int main(){
std::ios::sync_with_stdio(0), std::cin.tie(0);
int n, m;
std::cin >> n;
for (int i = 1; i <= n; ++ i) std::cin >> f[i];
build_tree(1, 1, n);
std::cin >> m;
for (; m; --m){
int L, R;
std::cin >> L >> R;
std::cout << query(1, 1, n, L, R) << "\n";
}
return 0;
}
/* SPOJ 1043 Segment_tree */
原文:https://www.cnblogs.com/Last--Whisper/p/14812732.html