AcWing 245. 你能回答这些问题吗
给定长度为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,
−1000≤A[i]≤1000
输入样例:
5 3
1 2 -3 4 5
1 2 3
2 2 -1
1 3 2
输出样例:
2
-1
这道题求的是l-r的最大连续区间和,我刚开始想到用dp去做o(n)级别的,但是没想到的是,这是一个动态变化的最大连续区间和,我就在想怎么去做呢。(我也是刚开始设计线段树),于是我就仔细地看了一遍y总的视频。
首先我们要开始build
我了解到线段树一定要保证完备性,y总提出了左右两个子树怎么求最大区间和的方法。
最大区间和我们求出来了,但是我们的最大前缀和最大后缀怎么求呢?
接下来是最大前缀的求解方法(最大后缀同理)。
根节点最大前缀等于max(左节点的最大前缀,左节点的和+右边的最大前缀)
sum操作就很简单了,左子树的sum+右子树的sum
最后实现query操作。
query操作我觉得学起来是最细节也是最难理解的地方
首先query返回的不是一个树,因为进行左右子树确定最大连续区间和需要(sum,lmax,rmax)这三个数,所以我们就把返回值变成struct这样就很容易轻松的进行一个pushup的操作返回我们想要得到的答案。
Node query(int u,int l,int r)
{
if(l<=tr[u].l&&tr[u].r<=r) return tr[u];
else
{
int mid=tr[u].l+tr[u].r>>1;
if(r<=mid) return query(u<<1,l,r);
else if(l>mid) return query(u<<1|1,l,r);
else
{
auto left=query(u<<1,l,r);
auto right=query(u<<1|1,l,r);
Node res;
pushup(res,left,right);
return res;
}
}
}
最终代码如下:
#include
#include
using namespace std;
const int N=5e5+10;
struct Node
{
int l,r;
int sum;
int rmax;
int lmax;
int tmax;
} tr[N*4];
int w[N];
int n,m;
void pushup(Node &root,Node &l,Node &r)
{
root.sum=l.sum+r.sum;
root.rmax=max(r.rmax,r.sum+l.rmax);
root.lmax=max(l.lmax,l.sum+r.lmax);
root.tmax=max(max(l.tmax,r.tmax),l.rmax+r.lmax);
}
void pushup(int u)
{
pushup(tr[u],tr[u<<1],tr[u<<1|1]);
}
void build(int u,int l,int r)
{
if(l==r)
{
tr[u]={l,r,w[l],w[l],w[l],w[l]};
}
else
{
tr[u]={l,r};
int mid=l+r>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
pushup(u);
}
}
void modify(int u,int x,int v)
{
if(tr[u].l==x&&tr[u].r==x) tr[u]={x,x,v,v,v,v};
else
{
int mid=tr[u].l+tr[u].r>>1;
if(x<=mid) modify(u<<1,x,v);
else
modify(u<<1|1,x,v);
pushup(u);
}
}
Node query(int u,int l,int r)
{
if(l<=tr[u].l&&tr[u].r<=r) return tr[u];
else
{
int mid=tr[u].l+tr[u].r>>1;
if(r<=mid) return query(u<<1,l,r);
else if(l>mid) return query(u<<1|1,l,r);
else
{
auto left=query(u<<1,l,r);
auto right=query(u<<1|1,l,r);
Node res;
pushup(res,left,right);
return res;
}
}
}
int main(void)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
build(1,1,n);
while(m--)
{
int k;
scanf("%d",&k);
if(k==1)
{
int a,b;
scanf("%d%d",&a,&b);
if(a>b)
swap(a,b);
cout<<query(1,a,b).tmax<;
}
else
{
int x,y;
scanf("%d%d",&x,&y);
modify(1,x,y);
}
}
}