https://vijos.org/p/1083
就是线段树啦,好像在洛谷也有怎么类似的一题;
struct tree{int l,r,x,y,v,sum;}T[1048576]
l,r就是区间啦,v表是这段区间的最优值;
sum是这一段的总和;
x是一定包括l点的最优值;
y是一定包括r点的最优值;
当然喽,因为一定要取公园所以可以负数;
更新
void up(int num){
int x=num*2,y=x+1;
T[num].v=max(T[x].v,T[y].v);
T[num].v=max(T[num].v,T[x].y+T[y].x);
T[num].sum=T[x].sum+T[y].sum;
T[num].x=max(T[x].x,T[x].sum+T[y].x);
T[num].y=max(T[y].y,T[y].sum+T[x].y);
}
不想讲什么了,反正是比较显然的啦,就是分类讨论;
然后我们查询答案,不是有一个区间l~r的;
这个区间会被线段树分成很多段;
那我们把这些段一个一个存下来从左到右合并成一个;
就好啦;
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#define Ll long long
using namespace std;
struct tree{int l,r,x,y,v,sum;}T[1048576],q[500000],temp;
int n,m,x,y,z,top;
void up(int num){
int x=num*2,y=x+1;
T[num].v=max(T[x].v,T[y].v);
T[num].v=max(T[num].v,T[x].y+T[y].x);
T[num].sum=T[x].sum+T[y].sum;
T[num].x=max(T[x].x,T[x].sum+T[y].x);
T[num].y=max(T[y].y,T[y].sum+T[x].y);
}
void maketree(int l,int r,int num){
T[num].l=l; T[num].r=r;
if(l==r){
scanf("%d",&T[num].v);
T[num].sum=T[num].x=T[num].y=T[num].v;
return;
}
int mid=l+r>>1;
maketree(l,mid ,num*2 );
maketree(mid+1,r,num*2+1);
up(num);
}
void outit(int x,int y,int num){
if(x<=T[num].l&&T[num].r<=y){
q[++top]=T[num];
return;
}
num=num+num;
if(T[num ].r>=x)outit(x,y,num );
if(T[num+1].l<=y)outit(x,y,num+1);
}
void init(int x,int v,int num){
if(T[num].l==T[num].r){
T[num].sum=T[num].x=T[num].y=T[num].v=v;
return;
}
num=num*2;
if(T[num ].r>=x)init(x,v,num );
if(T[num+1].l<=x)init(x,v,num+1);
up(num/2);
}
int main()
{
scanf("%d%d",&n,&m);
maketree(1,n,1);
while(m--){
scanf("%d%d%d",&z,&x,&y);
if(z==1){
if(x>y)swap(x,y);
top=0;
outit(x,y,1);
for(int i=2;i<=top;i++){
int x=i-1,y=i;
temp.v=max(q[x].v,q[y].v);
temp.v=max(temp.v,q[x].y+q[y].x);
temp.sum=q[x].sum+q[y].sum;
temp.x=max(q[x].x,q[x].sum+q[y].x);
temp.y=max(q[y].y,q[y].sum+q[x].y);
q[i]=temp;
}
printf("%d\n",q[top].v);
}else init(x,y,1);
}
}