tyvj 1427 小白逛公园(线段树中级,单点修改,动态最大连续和)

题意:
区间[1, n],开始给出初值。
m个操作,包括单点修改和区间最大连续和询问。
思路:
重点在两个地方
1)维护,最大连续和可能在左半区间或右半区间,也可能跨越中点,为此我们需要对一个节点维护最大前缀和,最大后缀和,最大连续和,总和这四个变量。
2)查询,一个区间查询,覆盖了树上一些连续的节点,所以我们应该在查询的过程中把这些节点,相邻的两两合并,最后合并成一个节点返回。

借鉴了CLJ的代码,用失效节点来代替不存在的节点。感觉代码精炼了很多,+操作也得到复用了。写起来真的很溜。。
参考文章:
http://blog.csdn.net/jiangzh7/article/details/8745213
http://wjmzbmr.com/archives/vijos1083_white_the_park/

#define lson(x) ((x)<<1)
#define rson(x) (((x)<<1)+1)

struct node {
    int pre_sum, suf_sum, tot_sum, sub_max;
    node(int x = 0):pre_sum(0), suf_sum(0), tot_sum(x), sub_max(0){}
};

int v[Maxn+5];
node a[Maxn*4];
const node none(-inf); // 失效节点

node operator + (const node & lhs, const node & rhs) {
    if (lhs.tot_sum == -inf) return rhs;
    if (rhs.tot_sum == -inf) return lhs;
    node ret;
    ret.pre_sum = max (lhs.pre_sum, lhs.tot_sum + rhs.pre_sum);
    ret.suf_sum = max (rhs.suf_sum, rhs.tot_sum + lhs.suf_sum);
    ret.sub_max = max (max (lhs.sub_max, rhs.sub_max), lhs.suf_sum + rhs.pre_sum);
    ret.tot_sum = lhs.tot_sum + rhs.tot_sum;
    return ret;
}

void seg_edit(int L, int R, int o, int p, int x) {
    if (L == R) {
        a[o].pre_sum = a[o].suf_sum = a[o].sub_max = a[o].tot_sum = x;
        return;
    }
    int lc = lson(o), rc = rson(o), mid = (L+R) >> 1;
    if (p <= mid) {
        seg_edit(L, mid, lc, p, x);
    }
    else {
        seg_edit(mid+1, R, rc, p, x);
    }
    a[o] = a[lc] + a[rc];
}

node seg_query(int L, int R, int o, int qL, int qR) {
    if (qR < L || qL > R) return none;
    if (qL <= L && R <= qR) {return a[o];}
    int mid = (L+R)>>1;
    return seg_query(L, mid, lson(o), qL, qR) + seg_query(mid+1, R, rson(o), qL, qR);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值