SPOJ 1557 Can you answer these queries II(GSS2 线段树)

转载请注明出处,谢谢http://blog.csdn.net/acm_cxlove/article/details/7854526       by---cxlove 

题目:求出区间的最大子段和,而且相同的数只能计算一次

http://www.spoj.pl/problems/GSS2/ 

嘛~~~这个题还是很不错的,不会,哭~~~~喵

在线的处理不了,只能离线处理

按询问区间的右端点排序,然后依次枚举a[i],pos[a[i]]表示对于数字a[i],上一个位置在哪

那么只需要将pos[a[i]]与i之间的部分全部加上a[i]
当查询的右区间为当前更新的位置的时候,查询便是历史区间最值。

但是实现起来并不简单~~~

维护4个值:old_cover  历史最大更新  old_max  历史最大值

                    now_cover 当前的更新值  now_max 当前区间的最大值

具体的看代码吧,各种纠结,尤其是Push_Down部分

#include<iostream>
#include<cstdio>
#include<map>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<algorithm>
#include<set>
#define inf (1ull<<63)-1
#define N 100005
#define maxn 100005
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
#define pb(a) push_back(a)
#define mem(a,b) memset(a,b,sizeof(a))
#define eps 1e-9
#define zero(a) fabs(a)<eps
#define LL long long
#define ULL unsigned long long
#define lson (step<<1)
#define rson (step<<1|1)
#define MOD 1000000007
#define mp(a,b) make_pair(a,b)
using namespace std;
struct Node{
	int left,right;
	int old_max,now_max,old_cover,now_cover;
}L[N*4];
struct Que{
	int left,right,id;
	bool operator<(const Que t)const{
		return right<t.right;
	}
}Q[N];
int n,q,a[N],pos[N*2+5],ans[N];
void Bulid(int step,int l,int r){
	L[step].left=l;
	L[step].right=r;
	L[step].old_max=L[step].now_max=L[step].now_cover=L[step].old_cover=0;
	if(l==r) return;
	int m=(l+r)/2;
	Bulid(lson,l,m);
	Bulid(rson,m+1,r);
}
void Push_Down(int step){
	L[lson].old_cover=max(L[lson].old_cover,L[lson].now_cover+L[step].old_cover);
	L[rson].old_cover=max(L[rson].old_cover,L[rson].now_cover+L[step].old_cover);

	L[lson].old_max=max(L[lson].old_max,L[lson].now_max+L[step].old_cover);
	L[rson].old_max=max(L[rson].old_max,L[rson].now_max+L[step].old_cover);

	L[lson].now_cover+=L[step].now_cover;
	L[rson].now_cover+=L[step].now_cover;

	L[lson].now_max+=L[step].now_cover;
	L[rson].now_max+=L[step].now_cover;

	L[step].now_cover=L[step].old_cover=0;
}
void Push_Up(int step){
	L[step].now_max=max(L[lson].now_max,L[rson].now_max);
	L[step].old_max=max(L[lson].old_max,L[rson].old_max);
}
void Update(int step,int l,int r,int c){
	if(L[step].left==l&&L[step].right==r){
		L[step].old_cover=max(L[step].old_cover,L[step].now_cover+=c);
		L[step].old_max=max(L[step].old_max,L[step].now_max+=c);
		return;
	}
	Push_Down(step);
	int m=(L[step].left+L[step].right)/2;
	if(r<=m) Update(lson,l,r,c);
	else if(l>m) Update(rson,l,r,c);
	else{
		Update(lson,l,m,c);
		Update(rson,m+1,r,c);
	}
	Push_Up(step);
}
int Query(int step,int l,int r){
	if(L[step].left==l&&L[step].right==r)
		return L[step].old_max;
	Push_Down(step);
	int m=(L[step].left+L[step].right)/2;	
	if(r<=m) return Query(lson,l,r);
	else if(l>m) return Query(rson,l,r);
	else return max(Query(lson,l,m),Query(rson,m+1,r));
}
int main(){
	while(scanf("%d",&n)!=EOF){
		Bulid(1,1,n);
		for(int i=1;i<=n;i++)
			scanf("%d",&a[i]);
		scanf("%d",&q);
		for(int i=0;i<q;i++){
			scanf("%d%d",&Q[i].left,&Q[i].right);
			Q[i].id=i;
		}
		sort(Q,Q+q);
		mem(pos,0);
		for(int i=1,j=0;i<=n;i++){
			Update(1,pos[a[i]+N]+1,i,a[i]);	
			pos[a[i]+N]=i;
			while(j<q&&Q[j].right==i){
				ans[Q[j].id]=Query(1,Q[j].left,Q[j].right);
				j++;
			}
			if(j>=q) break;
		}
		for(int i=0;i<q;i++) printf("%d\n",ans[i]);
	}
	return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值