SPOJ系列 —— SPOJ 1043

SPOJ 1043

#线段树

想了想还是给题面:

You are given a sequence (A[1], A[2], cdots, A[N] . ( |A[i]| le 15007 , 1 le N le 50000 )). A query is defined as follows:

  • (verb|Query(x,y) = Max { a[i]+a[i+1]+...+a[j]; x ≤ i ≤ j ≤ y }.|)

Given (M) queries, your program must output the results of these queries.

其实就是维护一个区间中的最长子段和。我们可以考虑维护一个区间,分别维护4个attribute:

  • sum ;代表区间和
  • pre ;代表区间最大前缀和
  • suf ;代表区间最大后缀和
  • sub ;代表区间最大子段和

考虑以下情况,父区间为(Tr),其两个子区间分别为(Tr_l, Tr_r)。我们分别讨论如何维护每个attribute:

  • 对于sum, 直接维护即可:Tr.sum = Trl.sum + Trr.sum
  • 对于sub,有三种情况,分别是(Tr_l)单独贡献, (Tr_r)单独贡献以及(Tr_l)贡献后缀,(Tr_r)贡献前缀,所以维护方式为: Tr.sub = max(Trl.sub, Trr.sub, Trl.suf + Trr.pre)
  • 对于pre ,有两种情况,分别是(Tr_l)单独贡献前缀,(Tr_l)贡献整个区间以及(Tr_r)贡献前缀,所以维护方式:Tr.pre = max(Trl.pre, Trl.sum + Trr.pre)
  • 对于suf同理,Tr.suf = max(Trr.suf, Trr.sum + Trl.suf)

在确定如何维护区间更新之后直接写线段树即可:

#include <bits/stdc++.h>
using namespace std;

const int maxn = 5e4 + 50;

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

int f[maxn];
struct Tr{
    int l, r, pre, suf, sub, sum;
    Tr () {}
    Tr (int _l, int _r, int v): l(_l), r(_r), sum(v){
        pre = suf = sub = sum;
    }
} tr[maxn << 2];

void pushup(int node){
    tr[node].sum = tr[lc(node)].sum + tr[rc(node)].sum;
    tr[node].sub = std::max({tr[lc(node)].sub, tr[rc(node)].sub, tr[lc(node)].suf + tr[rc(node)].pre});
    tr[node].pre = std::max(tr[lc(node)].pre, tr[lc(node)].sum + tr[rc(node)].pre);
    tr[node].suf = std::max(tr[rc(node)].suf, tr[rc(node)].sum + tr[lc(node)].suf);
}


void build_tree(int node, int start, int end){
    if (start == end) return tr[node] = Tr(start, end, f[start]), void();
    int mid = start + end >> 1;

    int left_node  = lc(node);
    int right_node = rc(node);
    build_tree(left_node , start, mid);
    build_tree(right_node, mid+1, end);
    pushup(node);
}

Tr _query(int node, int start, int end, int L, int R){
    if (L <= start && end <= R) return tr[node];
    int mid = start + end >> 1;
    if (mid < L)  return _query(rc(node), mid+1, end, L, R);
    if (mid >= R) return _query(lc(node), start, mid, L, R);

    Tr subl = _query(lc(node), start, mid, L, R);
    Tr subr = _query(rc(node), mid+1, end, L, R);

    Tr ret;
    ret.sum = subl.sum + subr.sum;
    ret.sub = std::max({subl.sub, subr.sub, subl.suf + subr.pre});
    ret.pre = std::max(subl.pre, subl.sum + subr.pre);
    ret.suf = std::max(subr.suf, subr.sum + subl.suf);

    return ret;
}

int query(int node, int start, int end, int L, int R){
    Tr ans = _query(node, start, end, L, R);
    return ans.sub;
}

const int rt = 1; // start from 1
int main(){
    std::ios::sync_with_stdio(0), std::cin.tie(0);
    int n, m; 
    std::cin >> n; 
    for (int i = 1; i <= n; ++ i) std::cin >> f[i];
    build_tree(1, 1, n);

    std::cin >> m;
    for (; m; --m){
        int L, R;
        std::cin >> L >> R;
        std::cout << query(1, 1, n, L, R) << "
";
    }

    return 0;
}   

/* SPOJ 1043 Segment_tree */
原文地址:https://www.cnblogs.com/Last--Whisper/p/14812732.html