POJ 3468 A Simple Problem with Integers // 线段树 区间更新

题目描述

POJ 3468 A Simple Problem with Integers

解题思路

题目大意:
对给定的一段区间支持下列操作:
1) 对区间[l, r] 的所有数, 增加(或减少)某个值
2) 查询区间[l, r] 的和
线段树成段更新的类型题, 具体看注释~^ ^

参考代码

#include <stdio.h>
#define lson rt<<1
#define rson rt<<1|1
#define mid ((l+r) >> 1)
typedef __int64 ll;
const int MAX_N = 100010;
struct SegTree{
    ll sum, add; // sum 是 区间的和, add 是延迟标记
}node[MAX_N << 2];

void pushup(int rt){
    node[rt].sum = node[lson].sum + node[rson].sum;
}

// 延迟更新
void pushdown(int rt, int len){
    if (node[rt].add){ // 如果根节点有延迟标记的话
        node[lson].add += node[rt].add; // 左儿子加上延迟的值
        node[rson].add += node[rt].add; // 右儿子加上延迟的值
        // 每个区间的和 在原来的基础上 再加上 由于延迟产生的差值 = 区间长度 * 延迟的大小
        node[lson].sum += (len - (len >> 1)) * node[rt].add;
        node[rson].sum += (len >> 1) * node[rt].add;
        node[rt].add = 0; // 因为已经释放下去了, 所以要去掉根节点的延迟标记
    }
}

// 建树
void build(int l, int r, int rt){
    node[rt].add = 0;
    if (l == r){
        scanf("%I64d", &node[rt].sum);
        return ;
    }
    build(l, mid, lson);
    build(mid+1, r, rson);
    pushup(rt);
}

//区间更新
void update(int L, int R, int add, int l, int r, int rt){
    int len = (r - l + 1);
    if (L <= l && r <= R){
        node[rt].add += add;
        node[rt].sum += len * add;
        return ;
    }
    pushdown(rt, len); // 释放延迟标记
    if (L <= mid)   update(L, R, add, l, mid, lson);
    if (R > mid)    update(L, R, add, mid+1, r, rson);
    pushup(rt);
}

ll query(int L, int R, int l, int r, int rt){
    int len = (r - l + 1);
    if (L <= l && r <= R){
        return node[rt].sum;
    }
    pushdown(rt, len); // 查询时也要释放延迟标记
    ll ans = 0; 
    if (L <= mid)   ans += query(L, R, l, mid, lson);
    if (R > mid)    ans += query(L, R, mid+1, r, rson);
    pushup(rt);
    return ans;
}

int main(){
    int N, Q, x, y, z;
    char c;
    while (~scanf("%d %d", &N, &Q)){
        build(1, N, 1);
        while (Q--){
            scanf(" %c %d %d", &c, &x, &y);
            if (c == 'Q')
                printf("%I64d\n", query(x, y, 1, N, 1));
            else{
                scanf("%d", &z);
                update(x, y, z, 1, N, 1);
            }
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值