uva 1400 Ray, Pass me the dishes!(线段树, 分治法求最大连续和)

参照RJ大大的代码写的。非常经典的一题!!!

有很多易错的地方。。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <cassert>
#include <algorithm>
#include <cmath>
#include <limits>
#include <set>
#include <time.h>
#include <errno.h>

using namespace std;

#define MIN(a, b) a < b ? a : b
#define MAX(a, b) a > b ? a : b
#define F(i, n) for (int i=0;i<(n);++i)
#define REP(i, s, t) for(int i=s;i<=t;++i)
#define UREP(i, s, t) for(int i=s;i>=t;--i)
#define REPOK(i, s, t, o) for(int i=s;i<=t && o;++i)
#define MEM0(addr, size) memset(addr, 0, size)
#define LBIT(x) x&-x

#define PI 3.1415926535897932384626433832795
#define HALF_PI 1.5707963267948966192313216916398
#define eps 1e-15

#define MAXN 500000
#define MAXM 1000
#define MOD 20071027

typedef long long LL;

const double maxdouble = numeric_limits<double>::max();
const int INF = 0x7FFFFFFF;

typedef pair<int,int> Interval;

LL prefix_sum[MAXN + 10];

LL sum(int L, int R) {
  return prefix_sum[R] - prefix_sum[L-1];
}

LL sum(Interval p) {
  return sum(p.first, p.second);
}

Interval better(Interval a, Interval b) {
  if(sum(a) != sum(b)) return sum(a) > sum(b) ? a : b;
  return a < b ? a : b; // 利用pair自带的字典序
}

const int maxnode = 1 << 21; // 修改以确保足够大
struct IntervalTree {
    int max_suffix[maxnode+1];
    int max_prefix[maxnode+1];
    Interval max_sub[maxnode+1];
    int length;
    int p, v;
    int qL, qR;

    void init(int n) {
        length = n;
        //memset(minv, 0, sizeof(int) * (n + 5));
    }
    //_query的封装
    Interval query(int L, int R) {
        qL = L;
        qR = R;
        return _query(1, 1, length);
    }

    void build(int o, int L, int R) {
        if (L == R) {
            max_sub[o] = make_pair(L, L);
            max_prefix[o] = L;
            max_suffix[o] = L;
        } else {
            int M = L + (R-L)/2;
            int lc = 2*o, rc = 2*o+1;
            LL v1, v2; // 注意 sum 会溢出int,要用LL
            build(lc, L, M);
            build(rc, M+1, R);

            // 递推preffix
            v1 = sum(L, max_prefix[lc]);
            v2 = sum(L, max_prefix[rc]);
            //if(v1 == v2) max_prefix[o] = min(max_prefix[lc], max_prefix[rc]);
            //else max_prefix[o] = v1 > v2 ? max_prefix[lc] : max_prefix[rc];
            max_prefix[o] = v1 >= v2 ? max_prefix[lc] : max_prefix[rc];// 因为要求字典序最小

            // 递推suffix
            v1 = sum(max_suffix[lc], R);
            v2 = sum(max_suffix[rc], R);
            //if(v1 == v2) max_suffix[o] = min(max_suffix[lc], max_suffix[rc]);
            //else max_suffix[o] = v1 > v2 ? max_suffix[lc] : max_suffix[rc];
            max_suffix[o] = v1 >= v2 ? max_suffix[lc] : max_suffix[rc];

            max_sub[o] = better(max_sub[lc], max_sub[rc]);
            max_sub[o] = better(max_sub[o], make_pair(max_suffix[lc], max_prefix[rc]));
        }
    }

    Interval _query_preffix(int o, int L, int R) {
        if (max_prefix[o] <= qR) // L 是一定包含在查询区间中的
            return make_pair(L, max_prefix[o]);
        int M = L + (R-L)/2;
        int lc = 2*o, rc = 2*o+1;
        if (qR <= M)
            return _query_preffix(lc, L, M);
        Interval i = _query_preffix(rc, M+1, R);
        i.first = L;
        return better(i, make_pair(L, max_prefix[lc]));
    }

    Interval _query_suffix(int o, int L, int R) {
        if (max_suffix[o] >= qL)
            return make_pair(max_suffix[o], R);
        int M = L + (R-L)/2;
        int lc = 2*o, rc = 2*o+1;
        if (qL > M)
            return _query_suffix(rc, M+1, R);
        Interval i = _query_suffix(lc, L, M);
        i.second = R;
        return better(i, make_pair(max_suffix[rc], R));
    }

    Interval _query(int o, int L, int R) {
        if (qL <= L && qR >= R)
            return max_sub[o];
        int M = L + (R-L)/2;
        int lc = 2*o, rc = 2*o + 1;
        if (qR <= M)
            return _query(lc, L, M);
        if (qL > M)
            return _query(rc, M+1, R);

        Interval suffix = _query_suffix(lc, L, M); // 左半的后缀和
        Interval preffix = _query_preffix(rc, M+1, R); // 右半的前缀和

        Interval ret = better(_query(lc, L, M), _query(rc, M+1, R));
        ret = better(ret, make_pair(suffix.first, preffix.second)); // 和最大区间过中点的情况
        return ret;
    }
};

IntervalTree tree;

int main()
{
    int n, m;
    int tmp;
    int cases = 0;

    while(scanf("%d%d", &n, &m) != EOF) {
        prefix_sum[0] = 0;
        F(i, n) {
            scanf("%d",&tmp);
            prefix_sum[i+1] = prefix_sum[i] + tmp;
        }
        // build tree
        tree.init(n);
        tree.build(1, 1, n);

        printf("Case %d:\n", ++cases);

        F(i, m) {
            int l, r;
            scanf("%d%d",&l, &r);
            Interval interval = tree.query(l, r);
            printf("%d %d\n", interval.first, interval.second);
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值