• 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 */
    
  • 相关阅读:
    11G-使用跨平台增量备份减少可移动表空间的停机时间 XTTS (Doc ID 1389592.1)
    如何在asm上定位数据块
    log file switch (checkpoint incomplete)
    踩坑记录(git)-误提交target文件夹删除办法
    踩坑记录(java)-双层增强for调用remove(obj)报错 java.util.ConcurrentModificationException(并发修改异常)
    Zookeeper服务端的创建及简单的客户端创建节点
    SpringAOP(注解方式实现面向切面编程)之常用Before、After、Around
    EasyExcel示例(阿里巴巴)基于Maven
    Redis简单命令(部分示例代码)
    sqlserver日志处理不当而造成的隐患
  • 原文地址:https://www.cnblogs.com/Last--Whisper/p/14812732.html
Copyright © 2020-2023  润新知