luogu GSS系列的3道题

背景:

上次集训做的套题,还没来得及写 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));
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值