背景:
上次集训做的套题,还没来得及写
b
l
o
g
blog
blog。
题目传送门:
https://www.luogu.org/problemnew/show/SP1043
https://www.luogu.org/problemnew/show/SP1716
https://www.luogu.org/problemnew/show/SP2916
题意:
第一道题若干组询问,每组询问求一段区间的最大子段和。
第二道题就是加多了一个修改操作。
第三道题则是在左右端点在
[
x
1
,
y
1
]
[x_1,y_1]
[x1,y1],
[
x
2
,
y
2
]
[x_2,y_2]
[x2,y2]内的区间的最大字段和。
思路:
第一题和第二题:
线段树经典题目。
维护四个东西:整一段都选的和
d
d
d,从左到右(选最左端)的最大和
d
1
d1
d1,从中间往左右两端延伸的最大和
d
2
d2
d2,从右到左(选最右端)的最大和
d
3
d3
d3。
每一次根据这三个儿子的东西更新当前的父亲即可。
具体如下:
tr[now].d=tr[lc].d+tr[rc].d;
tr[now].d1=max(tr[lc].d1,tr[lc].d+tr[rc].d1);
tr[now].d2=max(max(tr[lc].d2,tr[rc].d2),tr[lc].d3+tr[rc].d1);
tr[now].d3=max(tr[rc].d3,tr[lc].d3+tr[rc].d);
自己画画图就知道了。
第三题:
显然没有给
x
1
,
y
1
,
x
2
,
y
2
x_1,y_1,x_2,y_2
x1,y1,x2,y2的范围,要分类讨论。
具体看代码。
S P 1043 SP1043 SP1043代码:
#include<cstdio>
#include<algorithm>
#define LL long long
using namespace std;
struct node{int l,r,lc,rc,d,d1,d2,d3;} tr[600010];
int n,m,len=0;
void build(int l,int r)
{
int now=++len,mid=(l+r)>>1;
tr[now]=(node){l,r,-1,-1,0,0,0,0};
if(l<r)
{
tr[now].lc=len+1; build(l,mid);
tr[now].rc=len+1; build(mid+1,r);
}
}
void change(int now,int x,int k)
{
if(tr[now].l==tr[now].r)
{
tr[now].d=tr[now].d1=tr[now].d2=tr[now].d3=k;
return;
}
int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)>>1;
if(x<=mid) change(lc,x,k); else change(rc,x,k);
tr[now].d=tr[lc].d+tr[rc].d;
tr[now].d1=max(tr[lc].d1,tr[lc].d+tr[rc].d1);
tr[now].d2=max(max(tr[lc].d2,tr[rc].d2),tr[lc].d3+tr[rc].d1);
tr[now].d3=max(tr[rc].d3,tr[lc].d3+tr[rc].d);
}
node findsum(int now,int l,int r)
{
if(l==tr[now].l&&r==tr[now].r) return tr[now];
int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)>>1;
if(r<=mid) return findsum(lc,l,r);
else if(l>mid) return findsum(rc,l,r);
else
{
node ans,a=findsum(lc,l,mid),b=findsum(rc,mid+1,r);
ans.d=a.d+b.d;
ans.d1=max(a.d1,a.d+b.d1);
ans.d2=max(max(a.d2,b.d2),a.d3+b.d1);
ans.d3=max(b.d3,a.d3+b.d);
return ans;
}
}
int main()
{
int x,y;
scanf("%d",&n);
build(1,n);
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
change(1,i,x);
}
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d %d",&x,&y);
node ans=findsum(1,x,y);
printf("%d\n",max(max(ans.d1,ans.d2),ans.d3));
}
}
S P 1716 SP1716 SP1716代码:
#include<cstdio>
#include<algorithm>
#define LL long long
using namespace std;
struct node{int l,r,lc,rc,d,d1,d2,d3;} tr[600010];
int n,m,len=0;
void build(int l,int r)
{
int now=++len,mid=(l+r)>>1;
tr[now]=(node){l,r,-1,-1,0,0,0,0};
if(l<r)
{
tr[now].lc=len+1; build(l,mid);
tr[now].rc=len+1; build(mid+1,r);
}
}
void change(int now,int x,int k)
{
if(tr[now].l==tr[now].r)
{
tr[now].d=tr[now].d1=tr[now].d2=tr[now].d3=k;
return;
}
int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)>>1;
if(x<=mid) change(lc,x,k); else change(rc,x,k);
tr[now].d=tr[lc].d+tr[rc].d;
tr[now].d1=max(tr[lc].d1,tr[lc].d+tr[rc].d1);
tr[now].d2=max(max(tr[lc].d2,tr[rc].d2),tr[lc].d3+tr[rc].d1);
tr[now].d3=max(tr[rc].d3,tr[lc].d3+tr[rc].d);
}
node findsum(int now,int l,int r)
{
if(l==tr[now].l&&r==tr[now].r) return tr[now];
int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)>>1;
if(r<=mid) return findsum(lc,l,r);
else if(l>mid) return findsum(rc,l,r);
else
{
node ans,a=findsum(lc,l,mid),b=findsum(rc,mid+1,r);
ans.d=a.d+b.d;
ans.d1=max(a.d1,a.d+b.d1);
ans.d2=max(max(a.d2,b.d2),a.d3+b.d1);
ans.d3=max(b.d3,a.d3+b.d);
return ans;
}
}
int main()
{
int t,x,y;
scanf("%d",&n);
build(1,n);
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
change(1,i,x);
}
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d %d %d",&t,&x,&y);
switch(t)
{
case 0:change(1,x,y);break;
case 1:node ans=findsum(1,x,y);printf("%d\n",max(max(ans.d1,ans.d2),ans.d3));break;
}
}
}
S P 2916 SP2916 SP2916代码:
#include<cstdio>
#include<algorithm>
#define LL long long
using namespace std;
struct node{int l,r,lc,rc,d,d1,d2,d3;} tr[200010];
int n,m,len=0;
void build(int l,int r)
{
int now=++len,mid=(l+r)>>1;
tr[now]=(node){l,r,-1,-1,0,0,0,0};
if(l<r)
{
tr[now].lc=len+1; build(l,mid);
tr[now].rc=len+1; build(mid+1,r);
}
}
void change(int now,int x,int k)
{
if(tr[now].l==tr[now].r)
{
tr[now].d=tr[now].d1=tr[now].d2=tr[now].d3=k;
return;
}
int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)>>1;
if(x<=mid) change(lc,x,k); else change(rc,x,k);
tr[now].d=tr[lc].d+tr[rc].d;
tr[now].d1=max(tr[lc].d1,tr[lc].d+tr[rc].d1);
tr[now].d2=max(max(tr[lc].d2,tr[rc].d2),tr[lc].d3+tr[rc].d1);
tr[now].d3=max(tr[rc].d3,tr[lc].d3+tr[rc].d);
}
node findsum(int now,int l,int r)
{
if(l>r||l<=0||r<=0) return (node){0,0,0,0};
if(l==tr[now].l&&r==tr[now].r) return tr[now];
int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)>>1;
if(r<=mid) return findsum(lc,l,r);
else if(l>mid) return findsum(rc,l,r);
else
{
node ans,a=findsum(lc,l,mid),b=findsum(rc,mid+1,r);
ans.d=a.d+b.d;
ans.d1=max(a.d1,a.d+b.d1);
ans.d2=max(max(a.d2,b.d2),a.d3+b.d1);
ans.d3=max(b.d3,a.d3+b.d);
return ans;
}
}
int work(int x1,int y1,int x2,int y2)
{
if(x1==y1&&x2==y2) return findsum(1,x1,x2).d;
if(x1==x2&&y1==y2) return max(findsum(1,x1,y1).d1,max(findsum(1,x1,y1).d2,findsum(1,x1,y1).d3));
if(x1==x2) return max(findsum(1,x1,y1).d1,max(findsum(1,x1,y1).d2,findsum(1,x1,y1).d3+max(findsum(1,y1+1,y2).d1,0)));
if(y1==y2) return max(findsum(1,x2,y1).d3,max(findsum(1,x2,y1).d2,findsum(1,x2,y1).d1+max(findsum(1,x1,x2-1).d3,0)));
if(x1==y1) return findsum(1,x1,x2).d+max(findsum(1,x2+1,y2).d1,0);
if(x2==y2) return max(findsum(1,x1,y1-1).d3,0)+findsum(1,y1,y2).d;
if(y1==x2) return max(findsum(1,x1,y1-1).d3,0)+findsum(1,x2,y2).d1;
if(y1<x2) return max(findsum(1,x1,y1-1).d3,0)+findsum(1,y1,x2).d+max(findsum(1,x2+1,y2).d1,0);
if(y1>x2) return max(max(findsum(1,x1,x2-1).d3+findsum(1,x2,y1).d+findsum(1,y1+1,y2).d1,findsum(1,x2,y1).d2),
max(findsum(1,x1,x2-1).d3+findsum(1,x2,y1).d1,findsum(1,x2,y1).d3+findsum(1,y1+1,y2).d1));
}
int main()
{
int T,x1,y1,x2,y2,z;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
len=0;
build(1,n);
for(int i=1;i<=n;i++)
{
scanf("%d",&z);
change(1,i,z);
}
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
printf("%d\n",work(x1,y1,x2,y2));
}
}
}