題意
1、單點修改
2、求區間[l,r]內的最大子序列
題解
做法還算好想吧(如果做過類似題目
比如poj 的 hotel ?好像沒什麼差別的。
就是一棵線段樹每個節點要記四個值:左端點連續的和最大值,右端點連續的和的最大值,區間和,區間最大子序列和。
注意點:
1、在求和時因爲這個詢問區間是拼起來的,所以在query時返回最好是結構體,以便合併。(不用的話不知道怎麼做qwq)
2、pushup中左端點的連續和最大值爲左兒子的連續和最大值或者左兒子的和+右兒子的左端點連續和最大值,其他也是一個道理。
大概就這兩點是比較重要的吧tat(有時間就寫一下哦~)
//Suplex
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#define N 2000000
#define Segment_tree ST
using namespace std;
int n,m,opt,x,y;
struct ST{
int mx,s,ls,rs;
}t[N+N+N+N];
inline void pushup(ST &rt,ST lson,ST rson)
{
if(lson.rs<0 && rson.ls<0) rt.mx=max(lson.rs,rson.ls);
else{
rt.mx=0;
if(lson.rs>0) rt.mx=lson.rs;
if(rson.ls>0) rt.mx+=rson.ls;
}
rt.mx=max(rt.mx,max(lson.mx,rson.mx));
rt.ls=max(lson.ls,lson.s+rson.ls);
rt.rs=max(rson.rs,rson.s+lson.rs);
rt.s=lson.s+rson.s;
}
void build(int rt,int l,int r)
{
if(l==r){
scanf("%d",&t[rt].mx);
t[rt].s=t[rt].ls=t[rt].rs=t[rt].mx;
return;
}
int mid=(l+r)>>1;
build(rt+rt,l,mid);
build(rt+rt+1,mid+1,r);
pushup(t[rt],t[rt+rt],t[rt+rt+1]);
}
void modify(int rt,int l,int r,int x,int delta)
{
if(l==r){
t[rt].s=t[rt].ls=t[rt].rs=t[rt].mx=delta;
return;
}
int mid=(l+r)>>1;
if(x<=mid) modify(rt+rt,l,mid,x,delta);
else modify(rt+rt+1,mid+1,r,x,delta);
pushup(t[rt],t[rt+rt],t[rt+rt+1]);
}
ST query(int rt,int l,int r,int x,int y)
{
if(x<=l && r<=y) return t[rt];
int mid=(l+r)>>1;
if(y<=mid) return query(rt+rt,l,mid,x,y);
else if(x>mid) return query(rt+rt+1,mid+1,r,x,y);
else{
ST tmp,lson=query(rt+rt,l,mid,x,mid),rson=query(rt+rt+1,mid+1,r,mid+1,y);
pushup(tmp,lson,rson);
return tmp;
}
}
int main()
{
scanf("%d%d",&n,&m);
build(1,1,n);
while(m--){
scanf("%d%d%d",&opt,&x,&y);
if(opt==1){
if(x>y) swap(x,y);
printf("%d\n",query(1,1,n,x,y).mx);
}else modify(1,1,n,x,y);
}
return 0;
}