题意翻译
nn 个数,qq 次操作
操作0 x y
把A_xAx 修改为yy
操作1 l r
询问区间[l, r][l,r] 的最大子段和
感谢 @Edgration 提供的翻译
题目描述
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.
输入输出样例
输入样例#1: 复制
4
1 2 3 4
4
1 1 3
0 3 -3
1 2 4
1 3 3
输出样例#1: 复制
6
4
-3
分析:
见这篇博客
https://blog.csdn.net/SSL_ZYC/article/details/81951129
数组线段树模板:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<cmath>
#include<iostream>
#include<sstream>
#include<iterator>
#include<algorithm>
#include<string>
#include<vector>
#include<set>
#include<map>
#include<stack>
#include<deque>
#include<queue>
#include<list>
using namespace std;
const double eps = 1e-8;
typedef long long LL;
#define lson i<<1, l, m /// i*2
#define rson i<<1|1, m+1, r /// i*2+1
const int maxn=500000+5;
//线段树需要维护的信息
int sum[maxn*4]; //四倍
int lmaxn[maxn*4],rmaxn[maxn*4],dat[maxn*4];
int a[maxn],ans,pre;
///区间和sumsum,区间最大连续字段和datdat,
///紧靠左端的最大连续字段和lmaxlmax,紧靠右端的最大连续字段和rmaxrmax
//i节点收集子节点的统计结果
void PushUp(int i) //求和
{
sum[i]=sum[i<<1]+sum[i<<1|1];
lmaxn[i]=max(lmaxn[i<<1], sum[i<<1]+lmaxn[i<<1|1]);
rmaxn[i]=max(rmaxn[i<<1|1],sum[i<<1|1]+rmaxn[i<<1]);
dat[i]=max(max(dat[i<<1], dat[i<<1|1]),lmaxn[i<<1|1]+rmaxn[i<<1]);
}
//递归建立线段树
void build(int i,int l,int r)
{
if(l==r)
{
sum[i]=a[l];
lmaxn[i]=a[l];
rmaxn[i]=a[l];
dat[i]=a[l];
return ;
}
int m=(l+r)>>1;
build(lson);
build(rson);
PushUp(i);//收集子节点的结果
}
//在当前区间[l, r]内查询区间[ql, qr]间的目标值
//且能执行这个函数的前提是:[l,r]与[ql,qr]的交集非空
//其实本函数返回的结果也是 它们交集的目标值
void query(int ql,int qr,int i,int l,int r)
{
//目的区间包含当前区间
if(ql<=l && r<=qr)
{
ans=max(ans,dat[i]);//计算
ans=max(ans,pre+lmaxn[i]);
pre=max(rmaxn[i],pre+sum[i]);//维护pre
return ;
}
int m=(l+r)>>1;
int res=0;
if(ql<=m) query(ql,qr,lson);
if(m<qr) query(ql,qr,rson);
}
//本题是单点更新,所以是在区间[l,r]内使得第id数的值+val
//如果是区间更新,可以update的参数需要将id变为ql和qr
void update(int id,int val,int i,int l,int r)
{
if(l==r)
{
sum[i] = val;
lmaxn[i]=val;
rmaxn[i]=val;
dat[i]=val;
return ;
}
int m=(l+r)>>1;
if(id<=m) update(id,val,lson);
else update(id,val,rson);
PushUp(i);//时刻记住维护i节点统计信息正确性
}
int main()
{
int n;//节点总数
while(scanf("%d",&n)!=-1)
{
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
build(1,1,n);//建立线段树
int b,u,v;
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&b,&u,&v);
if(b==1)
{
ans=-1e9;pre=-1e9;
if(u>v) swap(u,v);
query(u,v,1,1,n);
printf("%d\n",ans);
}
else if(b==0) update(u,v,1,1,n);
}
}
return 0;
}
结构体线段树代码:
#include <cstdio>
#include <algorithm>
#define N 500010
using namespace std;
int a[N];
int n,m,w,x,y,z;
struct node //线段树
{
int l,r,sum,max,lmax,rmax;
}tree[N*4];
int maxx(int x,int y,int z)
{
return max(x,max(y,z));
}
void PushUp(int x)
{
tree[x].sum=tree[x*2].sum+tree[x*2+1].sum;
tree[x].lmax=max(tree[x*2].lmax,tree[x*2].sum+tree[x*2+1].lmax);
tree[x].rmax=max(tree[x*2+1].rmax,tree[x*2+1].sum+tree[x*2].rmax);
tree[x].max=maxx(tree[x*2].max,tree[x*2+1].max,tree[x*2].rmax+tree[x*2+1].lmax); //求出每个点的所有值
}
void make(int x) //建树
{
if (tree[x].l==tree[x].r) //叶子节点
{
tree[x].sum=a[tree[x].l];
tree[x].lmax=a[tree[x].l];
tree[x].rmax=a[tree[x].l];
tree[x].max=a[tree[x].l]; //只有一个可能,它本身
return;
}
int mid=(tree[x].l+tree[x].r)/2;
tree[x*2].l=tree[x].l;
tree[x*2].r=mid;
tree[x*2+1].l=mid+1;
tree[x*2+1].r=tree[x].r; //左右儿子的边界
make(x*2);
make(x*2+1);
PushUp(x);
}
node find(int x,int l,int r) //查找
{
if (tree[x].l==l&&tree[x].r==r) return tree[x]; //找到
if (tree[x].l==tree[x].r) return (node){0,0,0,0,0,0}; //不成立
int mid=(tree[x].l+tree[x].r)/2;
if (r<=mid) return (node)find(x*2,l,r);
if (l>mid) return (node)find(x*2+1,l,r);
node a=find(x*2,l,mid),b=find(x*2+1,mid+1,r),c;
c.sum=a.sum+b.sum;
c.lmax=max(a.lmax,a.sum+b.lmax);
c.rmax=max(b.rmax,b.sum+a.rmax);
c.max=maxx(a.max,b.max,a.rmax+b.lmax); //求答案
return c;
}
void add(int x,int y,int k) //修改
{
if (tree[x].l==y&&tree[x].r==y) //找到
{
tree[x].sum=k;
tree[x].lmax=k;
tree[x].rmax=k;
tree[x].max=k; //重新更新
return;
}
if (tree[x].l==tree[x].r) return;
int mid=(tree[x].l+tree[x].r)/2;
if (y<=mid)
{
add(x*2,y,k);
}
else
{
add(x*2+1,y,k);
}
PushUp(x);
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
tree[1].l=1;
tree[1].r=n;
make(1);
scanf("%d",&m);
while (m--)
{
scanf("%d%d%d",&z,&x,&y);
if (z)
{
if (x>y) swap(x,y);
find(1,x,y);
printf("%d\n",find(1,x,y).max);
}
else
{
add(1,x,y);
}
}
return 0;
}