样例
第一行两个整数n和m;表示n个数和m次询问
第二行n个整数,每个数绝对值不超过1000
接下来m行,每行三个整数,第一个k;
当k等于1,给出整数a,b求【a,b】区间的最大子段和,(a可能大于b)
当k等于2,给出整数p,s,把数组的第p个数改变成s
最大子段和
线段树维护最大子段和模版题
线段树每个节点中维护一个区间的四个信息:
s:区间和
ms:最大子段和
ls:紧靠着区间左端点的最大子段和
rs:紧靠着区间右端点的最大子段和
pushUp
建树时递归到 l == r 时,那么节点维护的四个信息都为a[l]
重点在节点信息如何从左右儿子节点产生;即pushUp函数
s:左右儿子节点的s的和
tree[root].s = tree[root<<1].s + tree[root<<1|1].s;
ms:左右儿子节点的ms和左儿子的rs加右儿子ls的最大值
tree[root].ms = max(tree[root<<1].ms, tree[root<<1|1].ms);
tree[root].ms = max(tree[root].ms, tree[root<<1].rs + tree[root<<1|1].ls);
ls:左儿子的ls和左儿子的s加右儿子的ls的最大值
tree[root].ls = max(tree[root<<1].ls, tree[root<<1].s + tree[root<<1|1].ls);
rs:右儿子的rs和右儿子的s加左儿子的rs的最大值
tree[root].rs = max(tree[root<<1|1].rs, tree[root<<1|1].s + tree[root<<1].rs);
query
当节点的区间完全等于查询区间才能将节点return;
如果查询区间在节点的左儿子直接递归查询左儿子,如果在右儿子则查询右儿子;
如果查询区间横跨左右儿子则需要查询把查询区间分成两部分,分别查询左右儿子,两次查询会得到两个部分的节点信息,通过这两个信息得到完整的查询区间的信息,这个就和pushUp一样了
node query(int root, int l, int r){
if(tree[root].l == l && tree[root].r == r){
node res = tree[root];
return res;
}
int mid = (tree[root].l + tree[root].r)>>1;
if(r <= mid) return query(root<<1, l, r);
else if(l > mid) return query(root<<1|1, l, r);
else{
node resL, resR, res;
resL = query(root<<1, l, mid);
resR = query(root<<1|1, mid+1, r);
res.s = resL.s + resR.s;
res.ms = max(resL.ms, resR.ms);
res.ms = max(res.ms, resL.rs + resR.ls);
res.ls = max(resL.ls, resL.s + resR.ls);
res.rs = max(resR.rs, resR.s + resL.rs);
return res;
}
}
完整代码【模版】
#include <bits/stdc++.h>
#define maxn 500100
using namespace std;
int a[maxn];
struct node{
int l, r;
int ms, s, ls, rs;
}tree[maxn<<2];
void pushUp(int root){
tree[root].s = tree[root<<1].s + tree[root<<1|1].s;
tree[root].ms = max(tree[root<<1].ms, tree[root<<1|1].ms);
tree[root].ms = max(tree[root].ms, tree[root<<1].rs + tree[root<<1|1].ls);
tree[root].ls = max(tree[root<<1].ls, tree[root<<1].s + tree[root<<1|1].ls);
tree[root].rs = max(tree[root<<1|1].rs, tree[root<<1|1].s + tree[root<<1].rs);
}
void build(int root, int l, int r){
tree[root].l = l;
tree[root].r = r;
if(l == r){
tree[root].ms = tree[root].s = tree[root].rs = tree[root].ls = a[l];
return;
}
int mid = (l + r)>>1;
build(root<<1, l, mid);
build(root<<1|1, mid+1, r);
pushUp(root);
}
void change(int root, int pos, int num){
if(tree[root].l == tree[root].r && tree[root].l == pos){
tree[root].s = tree[root].ms = tree[root].ls = tree[root].rs = num;
return;
}
int mid = (tree[root].l + tree[root].r)>>1;
if(pos <= mid) change(root<<1, pos, num);
else change(root<<1|1, pos, num);
pushUp(root);
}
node query(int root, int l, int r){
if(tree[root].l == l && tree[root].r == r){
node res = tree[root];
return res;
}
int mid = (tree[root].l + tree[root].r)>>1;
if(r <= mid) return query(root<<1, l, r);
else if(l > mid) return query(root<<1|1, l, r);
else{
node resL, resR, res;
resL = query(root<<1, l, mid);
resR = query(root<<1|1, mid+1, r);
res.s = resL.s + resR.s;
res.ms = max(resL.ms, resR.ms);
res.ms = max(res.ms, resL.rs + resR.ls);
res.ls = max(resL.ls, resL.s + resR.ls);
res.rs = max(resR.rs, resR.s + resL.rs);
return res;
}
}
void __swap(int &x, int &y){
int t = x;
x = y;
y = t;
}
int main(){
int n, m;
while(~scanf("%d%d", &n, &m)){
for(int i = 1; i <= n; i++){
scanf("%d", &a[i]);
}
build(1, 1, n);
while(m--){
int op, x, y;
scanf("%d%d%d", &op, &x, &y);
if(op == 1){
if(x > y) __swap(x, y);
printf("%d\n", query(1, x, y).ms);
}
else{
change(1, x, y);
}
}
}
}