UVa-1400 - "Ray, Pass me the dishes!"

题目大意:

已知一个数列。

每次询问x、y,求在区间 [x,y] 中,数字和最大的段i、j

分析:

线段数。分别记录前缀和最大,后缀和最大,以及区间和最大的位置即可

程序:

#include <iostream>
#include <cstdio>
#include <cstdlib>

using namespace std;

#define LL long long

const int Max_N = 1000010;

int n_num, n_req;
LL num[Max_N], sum[Max_N];

typedef pair<int, int> Interval;

inline LL Sum(int x, int y)
{
	return sum[y] - sum[x - 1];
}

inline LL Sum(Interval x)
{
	return Sum(x.first, x.second);
}

inline Interval Better(Interval x, Interval y)
{
	if(Sum(x) == Sum(y))
		return x < y ? x : y;
	else
		return Sum(x) < Sum(y) ? y : x;
}

struct Interval_Tree
{
	int max_suffix[Max_N];
	int max_prefix[Max_N];
	Interval max_sub[Max_N];
	void Build(int root, int l, int r)
	{
		if(l == r)
		{
			max_suffix[root] = max_prefix[root] = l;
			max_sub[root] = make_pair(l, l);
		}
		else
		{
			int mid = (l + r) >> 1;
			int lc = root << 1;
			int rc = (root << 1) | 1;
			Build(lc, l, mid);
			Build(rc, mid + 1, r);
			
			LL v1 = Sum(l, max_prefix[lc]);
			LL v2 = Sum(l, max_prefix[rc]);
			if(v1 == v2)
				max_prefix[root] = min(max_prefix[lc], max_prefix[rc]);
			else
				max_prefix[root] = v1 > v2 ? max_prefix[lc] : max_prefix[rc];
			
			v1 = Sum(max_suffix[lc], r);
			v2 = Sum(max_suffix[rc], r);
			if(v1 == v2)
				max_suffix[root] = min(max_suffix[lc], max_suffix[rc]);
			else
				max_suffix[root] = v1 > v2 ? max_suffix[lc] : max_suffix[rc];
			
			max_sub[root] = Better(max_sub[lc], max_sub[rc]);
			max_sub[root] = Better(max_sub[root], make_pair(max_suffix[lc], max_prefix[rc]));
		}
	}
	
	Interval Query_Suffix(int root, int l, int r, int x)
	{
		if(max_suffix[root] >= x)
			return make_pair(max_suffix[root], r);
		int mid = (l + r) >> 1;
		int lc = root << 1;
		int rc = (root << 1) | 1;
		if(mid + 1 <= x)
			return Query_Suffix(rc, mid + 1, r, x);
		else
		{
			Interval ret = Query_Suffix(lc, l, mid, x);
			ret.second = r;
			return Better(ret, make_pair(max_suffix[rc], r));
		}
	}

	Interval Query_Prefix(int root, int l, int r, int y)
	{
		if(max_prefix[root] <= y)
			return make_pair(l, max_prefix[root]);
		int mid = (l + r) >> 1;
		int lc = root << 1;
		int rc = (root << 1) | 1;
		if(mid >= y)
			return Query_Prefix(lc, l, mid, y);
		else
		{
			Interval ret = Query_Prefix(rc, mid + 1, r, y);
			ret.first = l;
			return Better(ret, make_pair(l, max_prefix[lc]));
		}
	}

	Interval Query(int root, int l, int r, int x, int y)
	{
		if(x <= l && y >= r)
			return max_sub[root];
		int mid = (l + r) >> 1;
		int lc = root << 1;
		int rc = (root << 1) | 1;
		if(y <= mid)
			return Query(lc, l, mid, x, y);
		if(x >= mid + 1)
			return Query(rc, mid + 1, r, x, y);
		Interval ret1 = Query_Suffix(lc, l, mid, x);
		Interval ret2 = Query_Prefix(rc, mid + 1, r, y);
		Interval ret3 = Better(Query(lc, l, mid, x, y), Query(rc, mid + 1, r, x, y));
		return Better(ret3, make_pair(ret1.first, ret2.second));
	}
}tree;

void Init()
{
    sum[0] = 0;
    for(int i = 1; i <= n_num; i ++)
    {
        scanf("%lld", &num[i]);
        sum[i] = sum[i - 1] + num[i];
    }
    tree.Build(1, 1, n_num);
}

void Solve()
{
    for(int i = 0; i < n_req; i ++)
    {
        int x, y;
        scanf("%d%d", &x, &y);
        Interval ret = tree.Query(1, 1, n_num, x, y);
        printf("%d %d\n", ret.first, ret.second);
    }
}

int main()
{
    int cnt = 0;
    while(scanf("%d%d", &n_num, &n_req) == 2)
    {
        printf("Case %d:\n", ++ cnt);
        Init();
        Solve();
    }
    return 0;
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值