题目:
You are given a sequence A of N (N <= 50000) integers between -10000 and 10000. On this sequence you have to apply M (M <= 50000) operations:
modify the i-th element in the sequence or for given x y print max{Ai + Ai+1 + .. + Aj | x<=i<=j<=y }.
输入:
The first line of input contains an integer N. The following line contains N integers, representing the sequence A1..AN.
The third line contains an integer M. The next M lines contain the operations in following form:
0 x y: modify Ax into y (|y|<=10000).
1 x y: print max{Ai + Ai+1 + .. + Aj | x<=i<=j<=y }.
输出:
For each query, print an integer as the problem required.
样例输入:
4
1 2 3 4
4
1 1 3
0 3 -3
1 2 4
1 3 3
样例输出:
6
4
-3
题意:给出两个操作,一个是换数,一个是求区间最大子段和。
要求区间最大子段和我们需要用到四个数据。
tree[x].sum,表示区间x 的每个点的权值之和
tree[x].maxx 表示区间x 的最大子段和
tree[x].lmax ,表示区间x 的含点tree[x].l的最大子段和
tree[x].rmax,表示区间x xx的含点tree[x].r 的最大子段和
很明显,tree[x].sum=tree[x<<1].sum+tree[rt<<1|1].sum;
tree[x].lmax有多种可能:
1.完全位于左儿子中 2.占据了全部的左儿子,并有一部分在右儿子中,并且这一部分在右儿子的最左边
那么tree[x].lmax=max(tree[rt<<1].lmax,tree[rt<<1].sum+tree[rt<<1|1].lmax);
同理可得
tree[x].rmax=max(tree[rt<<1|1].rmax,tree[rt<<1|1].sum+tree[rt<<1].rmax);
最后还剩下一个tree[x].maxx有三种可能:
- 完全是右儿子的最大子段和
- 完全是左儿子的最大子段和
- 既有一部分在左儿子中,又有一部分在右儿子
所以tree[x].maxx=max(tree[rt<<1].rmax+tree[rt<<1|1].lmax,max(tree[rt<<1].maxx,tree[rt<<1|1].maxx)); (借鉴于https://blog.csdn.net/SSL_ZYC/article/details/81951129)
AC代码:
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn=50005;
int a[maxn];
struct tree
{
int lmax,rmax,maxx,sum;
}node[maxn<<2];
void pushup(int rt)
{
tree L=node[rt<<1],R=node[rt<<1|1];
node[rt].sum=L.sum+R.sum;
node[rt].lmax=max(L.lmax,L.sum+R.lmax);
node[rt].rmax=max(R.rmax,R.sum+L.rmax);
node[rt].maxx=max(L.rmax+R.lmax,max(L.maxx,R.maxx));
}
void build(int l,int r,int rt)
{
if(l==r)
{
node[rt].lmax=node[rt].maxx=node[rt].rmax=node[rt].sum=a[l];
return ;
}
int m=(l+r)>>1;
build(l,m,rt<<1);
build(m+1,r,rt<<1|1);
pushup(rt);
}
void update(int L,int c,int l,int r,int rt)
{
if(l==r)
{
node[rt].lmax=node[rt].maxx=node[rt].rmax=node[rt].sum=c;
return ;
}
int m=(l+r)>>1;
if(L<=m) update(L,c,l,m,rt<<1);
else update(L,c,m+1,r,rt<<1|1);
pushup(rt);
}
tree QuerY(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)
return node[rt];
int m=(l+r)>>1;
if(R<=m) return QuerY(L,R,l,m,rt<<1);
if(L>m) return QuerY(L,R,m+1,r,rt<<1|1);
tree LL=QuerY(L,m,l,m,rt<<1),RR=QuerY(m+1,R,m+1,r,rt<<1|1),res;
res.sum=LL.sum+RR.sum;
res.lmax=max(LL.lmax,LL.sum+RR.lmax);
res.rmax=max(RR.rmax,RR.sum+LL.rmax);
res.maxx=max(RR.lmax+LL.rmax,max(LL.maxx,RR.maxx));
return res;
}
int main()
{
int n,m;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
build(1,n,1);
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
if(a==1)
{
tree s=QuerY(b,c,1,n,1);
printf("%d\n",s.maxx);
}
else
{
update(b,c,1,n,1);
}
}
return 0;
}