思路:
我们知道pushup我们是根据子区间求解父区间的,然后连续区间和,我们并不确定子区间连续的是那一段,就假如子区间二中最大区间和的区间是(2——3),子区间二中最大的区间和是(5--6)父亲区间是(1--6)那这时候父亲区间连续区间的最大值应该分为三类情况讨论:(1)区间二的最大区间和(2)区间三的最大区间和(3)区间二的最大后缀和加上区间三的最大前缀和的结果,将这三类结果进行比较。所以我们需要在树的结构体中存储,最大区间和,最大前缀和,最大后缀和,然后最大前缀和,最大前缀和的求值,(这里记得最大前缀和是指父亲区间前n个数字的和最大,最大后缀和就是后n个数字的和最大)我们同样用上述例子举例,父亲区间的最大前缀和,我们分为两种情况:(1)区间二的最大前缀和(2)区间二的和+区间三的最大前缀和。后缀和同样两种情况:(1)区间三的最大后缀和(2)区间三的和+区间二的最大后缀和。因此结构体中我们还需要加入区间的和
u.summ=l.summ+r.summ;
u.tmax=max(max(l.tmax,r.tmax),l.rmax+r.lmax);
u.lmax=max(l.lmax,l.summ+r.lmax);
u.rmax=max(r.rmax,r.summ+l.rmax);
还有就是查询时,看我的代码注释吧,不想写了
代码:
#include<iostream>
using namespace std;
const int N=1e5+10;
int w[N];
struct Node{
int l,r;
int summ,tmax,lmax,rmax;
}tr[N*4];
void pushup(Node &u,Node &l,Node &r)
{
u.summ=l.summ+r.summ;
u.tmax=max(max(l.tmax,r.tmax),l.rmax+r.lmax);
u.lmax=max(l.lmax,l.summ+r.lmax);
u.rmax=max(r.rmax,r.summ+l.rmax);
}
void pushup(int u)
{
int l=u<<1;
int r=u<<1|1;
pushup(tr[u],tr[l],tr[r]);
}
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);
}
}
int 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)//整个u里面的都是我们要查找的范围
return tr[u];
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//前后部分都跟我们要查找的有交集,但是整个u里面的内容并不都是我们要查找的
{
Node left=query(u<<1,l,r);
Node right=query(u<<1|1,l,r);
Node res;
pushup(res,left,right);//因为left和right返回的值不一定是相邻的两个序号的最大连续和
return res;
}
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&w[i]);
build(1,1,n);
int k,x,y;
while(m--)
{
scanf("%d%d%d",&k,&x,&y);
if(k==1)
{
if(x>y)swap(x,y);
printf("%d\n",query(1,x,y).tmax);
}
else
{
modify(1,x,y);
}
}
return 0;
}
//5 3
// 1 2 -3 4 5
//1 2 3
//2 2 -1
//1 3 2