你能回答这些问题吗
给定长度为N的数列A,以及M条指令,每条指令可能是以下两种之一:
1、“1 x y”,查询区间 [x,y] 中的最大连续子段和,即 maxx≤l≤r≤y{∑ri=lA[i]}。
2、“2 x y”,把 A[x] 改成 y。
对于每个查询指令,输出一个整数表示答案。
输入格式
第一行两个整数N,M。
第二行N个整数A[i]。
接下来M行每行3个整数k,x,y,k=1表示查询(此时如果x>y,请交换x,y),k=2表示修改。
输出格式
对于每个查询指令输出一个整数表示答案。
每个答案占一行。
数据范围
N
≤
500000
,
M
≤
100000
N≤500000,M≤100000
N≤500000,M≤100000
输入样例:
5 3
1 2 -3 4 5
1 2 3
2 2 -1
1 3 2
输出样例:
2
-1
题解
写线段树的时候,我们先画一个父区间和两个子区间,看能不能只记录当前的状态就能通过子区间信息完整不漏的把父亲节点信息更新,如果不能则我们需要加状态。显然这道题只记录左右和最大区间和是不够的。所以加入做连续最大和右连续最大。
#include <bits/stdc++.h>
//#define int long long
using namespace std;
#define lson rt<<1
#define rson rt<<1|1
const int N=5e5+7;
struct Node{
int l,r;
int lmax,rmax,summax;
int sum;
}tr[N<<2];
int n,m,a[N];
void pushup(Node &u, Node &l, Node &r)
{
u.sum = l.sum + r.sum;
u.lmax = max(l.lmax, l.sum + r.lmax);
u.rmax = max(r.rmax, r.sum + l.rmax);
u.summax = max(max(l.summax, r.summax), l.rmax + r.lmax);
}
void pushup(int rt)
{
pushup(tr[rt],tr[lson],tr[rson]);
}
void build(int rt,int l,int r)
{
if(l==r) {
tr[rt]={l,l,a[l],a[l],a[l],a[l]};
return ;
}
tr[rt]={l,r};
int mid=l+r>>1;
build(lson,l,mid);
build(rson,mid+1,r);
pushup(rt);
}
Node query(int rt,int l,int r){
// cout<<"rt : "<<rt<<" l : "<<l<<" r : "<<r<<endl;
if(tr[rt].l>=l&&tr[rt].r<=r){
return tr[rt];
}
int mid=tr[rt].l+tr[rt].r>>1;
if(r<=mid) return query(lson,l,r);
else if(l>mid) return query(rson,l,r);
else{
auto left=query(lson,l,r);
auto right=query(rson,l,r);
Node res;
pushup(res,left,right);
return res;
}
}
void modify(int rt,int x,int c)
{
if(tr[rt].l==x&&tr[rt].r==x){
tr[rt]={x,x,c,c,c,c};
return ;
}
int mid=tr[rt].l+tr[rt].r>>1;
if(x<=mid) modify(lson,x,c);
else if(x>mid) modify(rson,x,c);
pushup(rt);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",a+i);
build(1,1,n);
// cout<<"--"<<endl;
for(int i=1;i<=m;i++){
int k,x,y; scanf("%d%d%d",&k,&x,&y);
if(k==1){
if(x>y) swap(x,y);
printf("%d\n",query(1,x,y).summax);
// cout<<"--"<<endl;
}else{
modify(1,x,y);
}
}
return 0;
}