[SPOJ]GSS系列(区间查询最大子段和问题)

1.GSS系列问题

s p o j spoj spoj上的一组数据结构问题
通常是查询最大子段和
找到这组题还是要感谢 a k i o i akioi akioi g j m gjm gjm
G S S = G r e a t e s t   S u m s   o f   S u b s e g m e n t s GSS=Greatest\ Sums \ of \ Subsegments GSS=Greatest Sums of Subsegments
这里是按我洛谷认为的难度顺序排序的
c o n t i n u e   u p d a t i n g . . . . . . continue\ updating...... continue updating......

2.GSS1

GSS系列第一题传送门
纯粹的维护最大子段和
怎么做呢?
我们考虑,在合并两颗子树的时候,最大子段和会在哪一部分
1.在左子树内=> u . a n s = l s o n . a n s u.ans=lson.ans u.ans=lson.ans
2.在右子树内=> u . a n s = r s o n . a n s u.ans=rson.ans u.ans=rson.ans
3.在中间=> u . a n s = l s o n . l m a x + r s o n . l m a x u.ans=lson.lmax+rson.lmax u.ans=lson.lmax+rson.lmax
其中 l m a x lmax lmax表示最大前缀和, r m a x rmax rmax表示最大后缀和
那么我们考虑最大前缀和和最大后缀和怎么确定
以最大前缀和为例
1.左子树的最大前缀和=> u . l m a x = l s o n . l m a x u.lmax=lson.lmax u.lmax=lson.lmax
2.左子树+右子树的最大前缀和=> u . l m a x = l s o n . s u m + r s o n . l m a x u.lmax=lson.sum+rson.lmax u.lmax=lson.sum+rson.lmax
其中 s u m sum sum表示区间和

然后就没了

# include <cstdio>
# include <algorithm>
# include <cstring>
# include <cmath>
# include <climits>
# include <iostream>
# include <string>
# include <queue>
# include <stack>
# include <vector>
# include <set>
# include <map>
# include <cstdlib>
# include <ctime>
using namespace std;

# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)

typedef long long ll;
const int N=1e5+5;
const int inf=0x7fffffff;
const double eps=1e-7;
template <typename T> void read(T &x){
   
   
	x=0;int f=1;
	char c=getchar();
	for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
	for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
	x*=f;
}

int n,m;
int a[N];

struct segment_tree{
   
   
	int sumf,sumb;
	int sum;
	int ans; 
	int l,r;
}seg[N<<2];

# define lc (u<<1)
# define rc (u<<1|1)

void pushup(int u){
   
   
	seg[u].sumf=max(seg[lc].sumf,seg[lc].sum+seg[rc].sumf);
	seg[u].sumb=max(seg[rc].sumb,seg[rc].sum+seg[lc].sumb);
	seg[u].sum=seg[lc].sum+seg[rc].sum;
	seg[u].ans=max(max(seg[lc].ans,seg[rc].ans),seg[lc].sumb+seg[rc].sumf);
} 

void build(int u,int l,int r){
   
   
	seg[u].l=l,seg[u].r=r;
	if(l==r){
   
   seg[u].sumf=seg[u].sumb=seg[u].sum=seg[u].ans=a[l];return;}
	int mid=l+r>>1;
	build(lc,l,mid);
	build(rc,mid+1,r);
	pushup(u);	
}

segment_tree query(int u,int l,int r){
   
   
	if(seg[u].l>=l&&seg[u].r<=r)return seg[u];
	int mid=seg[u].l+seg[u].r>>1;
	if(r<=mid)return query(lc,l,r);
	if(l>mid)return query(rc,l,r);
	segment_tree ls=query(lc,l,r),rs=query(rc,l,r),res;
	res.sumf=max(ls.sumf,ls.sum+rs.sumf);
	res.sumb=max(rs.sumb,rs.sum+ls.sumb);
	res.sum=ls.sum+rs.sum;
	res.ans=max(max(ls.ans,rs.ans),ls.sumb+rs.sumf);
	return res;
} 

int main()
{
   
   
	read(n);
	Rep(i,1,n)read(a[i]);
	build(1,1,n);
	read(m);
	Rep(i,1,m){
   
   
		int l,r;
		read(l),read(r);
		printf("%d\n",query(1,l,r).ans);	
	}
	return 0;
}

3.GSS3

传送门
这道题跟上一个没啥区别…
加一个 u p d a t e update update就好了

对了,这题可以算三倍经验
算上GSS1,还有一道小白逛公园

# include <cstdio>
# include <algorithm>
# include <cstring>
# include <cmath>
# include <climits>
# include <iostream>
# include <string>
# include <queue>
# include <stack>
# include <vector>
# include <set>
# include <map>
# include <cstdlib>
# include <ctime>
using namespace std;

# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)

typedef long long ll;
const int N=1e5+5;
const int inf=0x7fffffff;
const double eps=1e-7;
template <typename T> void read(T &x){
   
   
	x=0;int f=1;
	char c=getchar();
	for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
	for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
	x*=f;
}

int n,m;
int a[N];

struct segment_tree{
   
   
	int sumf,sumb;
	int sum;
	int ans; 
	int l,r;
}seg[N<<2];

# define lc (u<<1)
# define rc (u<<1|1)

void pushup(int u){
   
   
	seg[u].sumf=max(seg[lc].sumf,seg[lc].sum+seg[rc].sumf);
	seg[u].sumb=max(seg[rc].sumb,seg[rc].sum+seg[lc].sumb);
	seg[u].sum=seg[lc].sum+seg[rc].sum;
	seg[u].ans=max(max(seg[lc].ans,seg[rc].ans),seg[lc].sumb+seg[rc].sumf);
} 

void build(int u,int l,int r){
   
   
	seg[u].l=l,seg[u].r=r;
	if(l==r){
   
   seg[u].sumf=seg[u].sumb=seg[u].sum=seg[u].ans=a[l];return;}
	int mid=l+r>>1;
	build(lc,l,mid);
	build(rc,mid+1,r);
	pushup(u);	
}

void update(int u,int x,int k){
   
   
	if(seg[u].l==seg[u].r){
   
   seg[u].sumf=seg[u].sumb=seg[u].sum=seg[u].ans=k;return;}
	int mid=seg[u].l+seg[u].r>>1;
	if(x<=mid)update(lc,x,k);
	else update(rc,x,k);
	pushup(u);	
}

segment_tree query(int u,int l,int r){
   
   
	if(seg[u].l>=l&&seg[u].r<=r)return seg[u];
	int mid=seg[u].l+seg[u].r>>1;
	if(r<=mid)return query(lc,l,r);
	if(l>mid)return query(rc,l,r);
	segment_tree ls=query(lc,l,r),rs=query(rc,l,r),res;
	res.sumf=max(ls.sumf,ls.sum+rs.sumf);
	res.sumb=max(rs.sumb,rs.sum+ls.sumb);
	res.sum=ls.sum+rs.sum;
	res.ans=max(max(ls.ans,rs.ans),ls.sumb+rs.sumf);
	return res;
} 

int main()
{
   
   
	read(n);
	Rep(i,1,n)read(a[i]);
	build
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值