SPOJ - GSS1

线段树。
每个节点储存四个值,分别是:该区间内连续的最大值,从左边开始连续的最大值,从右边开始连续的最大值,整段的值。

我们知道,区间连续的最大值要么在最左边,要么在最右边,要么在中间的某一部分。

每次查询找出“完整覆盖”区间位置,从左往右暴力选择区间的起点和区间的终点。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef struct Segment{
	private: 
		static const int MAXN = 50000 + 100;
		static const ll INF = 0x3f3f3f3f3f3f3f3f;
		ll perm[MAXN], seg[MAXN * 4], area, lmax[MAXN * 4], rmax[MAXN * 4], sum[MAXN * 4];
		void push_up(int cur){
			int u = cur << 1, v = u + 1;
			seg[cur] = max(rmax[u] + lmax[v], max(seg[u], seg[v]));
			lmax[cur] = max(lmax[u], sum[u] + lmax[v]);
			rmax[cur] = max(rmax[v], sum[v] + rmax[u]);
			sum[cur] = sum[u] + sum[v];
		}
		void build(int cur, int L, int R){
			if(L > R)	return;
			if(L == R){
				seg[cur] = perm[L];
				lmax[cur] = perm[L];
				rmax[cur] = perm[L];
				sum[cur] = perm[L];
				return;
			}
			int u = cur << 1, v = u + 1, mid = L + (R - L) / 2;
			build(u, L, mid);
			build(v, mid + 1, R);
			push_up(cur);
		}
		bool Outside(int L, int R, int u, int v){
			return R < u || v < L;
		}
		bool Inside(int L, int R, int u, int v){
			return u <= L && R <= v;
		}
		void locate(int cur, int L, int R, int u, int v, int &k, int *A){
			if(Outside(L, R, u, v))	return;
			if(Inside(L, R, u, v)){
				A[k++] = cur;	return;
			}
			int mid = L + (R - L) / 2, uu = cur << 1, vv = uu + 1;
			locate(uu, L, mid, u, v, k, A);
			locate(vv, mid + 1, R, u, v, k, A);
		}
		ll query(int L, int R, int u, int v){
			static int pos[MAXN];
			int k = 0;
			ll res = -INF;
			locate(1, L, R, u, v, k, pos);
			for(int i = 0; i < k; i++){
				res = max(res, seg[pos[i]]);
				for(int j = i + 1; j < k; j++){
					ll temp = 0;
					for(int t = i + 1; t < j; t++)
						temp += sum[pos[t]];
					temp += rmax[pos[i]] + lmax[pos[j]];
					res = max(res, temp);
				}
			}
			return res;		
		}
	public:
		void build(){
			return build(1, 1, area);
		}
		ll query(int L, int R){
			return query(1, area, L, R);
		}
		void read(int n){
			area = n;
			for(int i = 1; i <= area; i++)	scanf("%lld", &perm[i]);
		}
}Segment;

Segment seg;

int main(void)
{
	int n;
	while(~scanf("%d", &n)){
		seg.read(n);
		seg.build();
		int k;
		scanf("%d", &k);
		while(k--){
			int u, v;	
			scanf("%d%d", &u, &v);
			printf("%lld\n", seg.query(u, v));
		}
	}
	return 0;
} 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值