题意:给出一个序列,每次操作修改一个数值或者查询一个区间内最大连续子序列的和。
思路:求和部分利用分治就好了,但是在求区间和的时候注意考虑,如果同时向左向右查询,最后结果不一定是左右相加,这里要特殊处理一下。
关于线段树的姿势,用结构体会比较好处理。
#include <bits/stdc++.h>
using namespace std;
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
typedef long long ll;
const int INF=0x3f3f3f3f;
const int maxn=5e5+10;
int n,m;
struct Node{
int sum;
int lsum;
int rsum;
int allsum;
}node[maxn<<2];
void PushUp(int rt){
node[rt].sum=node[rt<<1].sum+node[rt<<1|1].sum;
node[rt].lsum=max(node[rt<<1].lsum,node[rt<<1].sum+node[rt<<1|1].lsum);
node[rt].rsum=max(node[rt<<1|1].rsum,node[rt<<1|1].sum+node[rt<<1].rsum);
node[rt].allsum=max(max(node[rt<<1].allsum,node[rt<<1|1].allsum),node[rt<<1].rsum+node[rt<<1|1].lsum);
}
void build(int rt,int l,int r){
if(l==r){
scanf("%d",&node[rt].sum);
node[rt].lsum=node[rt].rsum=node[rt].allsum=node[rt].sum;
return ;
}
int mid=(l+r)>>1;
build(lson);
build(rson);
PushUp(rt);
}
void Update(int rt,int l,int r,int pos,int val){
if(l==r){
node[rt].sum=node[rt].lsum=node[rt].rsum=node[rt].allsum=val;
return ;
}
int mid=(l+r)>>1;
if(pos<=mid) Update(lson,pos,val);
else Update(rson,pos,val);
PushUp(rt);
}
Node Query(int rt,int l,int r,int L,int R){
if(L==l&&r==R) return node[rt];
int mid=(l+r)>>1;
if(R<=mid) return Query(lson,L,R);
else if(L>mid) return Query(rson,L,R);
else{
Node cur,r1,r2;
r1=Query(lson,L,mid);
r2=Query(rson,mid+1,R);
cur.sum=r1.sum+r2.sum;
cur.lsum=max(r1.lsum,r1.sum+r2.lsum);
cur.rsum=max(r2.rsum,r2.sum+r1.rsum);
cur.allsum=max(max(r1.allsum,r2.allsum),r1.rsum+r2.lsum);
return cur;
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("test.in","r",stdin);
freopen("test.out","w",stdout);
#endif
while(~scanf("%d%d",&n,&m)){
build(1,1,n);
int op,a,b;
while(m--){
scanf("%d%d%d",&op,&a,&b);
if(op==1){
if(a>b) swap(a,b);
printf("%d\n",Query(1,1,n,a,b).allsum);
}
else Update(1,1,n,a,b);
}
}
return 0;
}