GSS问题(一)

GSS问题(一)

又是喜闻乐见线段树内容辣!

GSS问题是一类以线段树为基础的有趣的问题

实际上这算是线段树的实际应用之一、但由于它实在经典又基础,所以实际上只是个模板题.

题面:

给出了序列 (A[1],A[2],…,A[N])((a[i]≤15007,1≤N≤50000))。查询定义如下:

查询 ((x,y)=max{a[i]+a[i+1]+...+a[j];x≤i≤j≤y})。 给定M个查询,程序必须输出这些查询的结果。

解释及思路

给出特定区间,让你求出其中连续一段数组之和最大是多少,如果全是正数那显然太脑残了,如果有负数就稍微难办些,正负夹杂就几乎停止思考.

但是我们曾接触过"最大子段和",一道经典的DP题,可不可以用DP来做?

DP的复杂度是(O(n)),是比较优的解法,但是我们本题有多次查询,并且每次查询的区间并不一定相同

这样一来复杂度最劣就成了(O(nm)),本题是过不了的,毕竟不可能只有1000次查询

开头即提到,本题是线段树板子题,考虑如何充分利用上线段树的特性

以下内容假设你知道线段树

重点

我们知道,线段树最为标志的结构特征就是节点多而有序,总可以代表那些不好表示的区间

同时,我们可以在这些节点上记录信息,完成区间信息的维护

对于这种"连续区间问题",我们该如何通过节点来完成维护呢

显然,每个答案区间,大概率都是由不少的节点合并而来的,

那么我们考虑,每个节点不光记录节点内的最大子段和,也记录节点左边连续最大的子段和,以及右边的.

这样一来,在进行合并的时候,将相邻两个节点的各自一端的信息进行合并就可以了

结合代码来看

代码:

#include<iostream>
#include<cstdio>
#define ll long long
#define ci const int &
using namespace std;
const int N=500005;
int n,m;
ll a[N];
struct node{
	ll l,r,maxn,sum;
	node(){
		l=r=maxn=sum=0;
	}
}nd[N<<2];
inline void build(ci k,ci l,ci r){
	if(l==r){
		nd[k].l=nd[k].r=nd[k].maxn=nd[k].sum=a[l];
		return ;
	}int mid=l+r>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	nd[k].sum=nd[k<<1].sum+nd[k<<1|1].sum;
	nd[k].l=nd[k<<1].l;
	nd[k].l=max(nd[k<<1].l,nd[k<<1].sum+nd[k<<1|1].l);
	nd[k].r=nd[k<<1|1].r;
	nd[k].r=max(nd[k<<1|1].r,nd[k<<1|1].sum+nd[k<<1].r);
	nd[k].maxn=max(max(nd[k<<1].maxn,nd[k<<1|1].maxn),nd[k<<1].r+nd[k<<1|1].l);
}
inline node query(ci k,ci l,ci r,ci x,ci y){
	if(x<=l&&r<=y) return nd[k];
	int mid=l+r>>1;
	node ret,le,ri;
	if(x<=mid) le=query(k<<1,l,mid,x,y);
	if(mid<y) ri=query(k<<1|1,mid+1,r,x,y);
	ret.sum=le.sum+ri.sum;
	if(x<=mid){
		ret.l=le.l;
		ret.l=max(le.l,le.sum+ri.l);	
	}
	else ret.l=ri.l;
	if(mid<y){
		ret.r=ri.r;
		ret.r=max(ri.r,ri.sum+le.r);	
	}else ret.r=le.r;
	if(x<=mid&&mid<y)
		ret.maxn=max(max(le.maxn,ri.maxn),le.r+ri.l);
	else if(x<=mid)
		ret.maxn=le.maxn;
	else
		ret.maxn=ri.maxn;
	return ret;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%lld",&a[i]);
	build(1,1,n);
	scanf("%d",&m);
	while(m--){
		int l,r;
		scanf("%d%d",&l,&r);
		node ans=query(1,1,n,l,r);
		printf("%lld
",ans.maxn);
	}return 0;
}
原文地址:https://www.cnblogs.com/648-233/p/12774985.html