poj 3648 线段树成段更新

      线段树成段更新需要用到延迟标记(或者说懒惰标记),简单来说就是每次更新的时候不要更新到底,用延迟标记使得更新延迟到下次需要更新or询问到的时候。延迟标记的意思是:这个区间的左右儿子都需要被更新,但是当前区间已经更新了。其主要使用了Lazy思想。

     Lazy思想:lazy-tag思想,记录每一个线段树节点的变化值,当这部分线段的一致性被破坏我们就将这个变化值传递给子区间,大大增加了线段树的效率。
在此通俗的解释Lazy(t偷懒)的意思,比如现在需要对[a,b]区间值进行加c操作,那么就从根节点[1,n]开始调用update函数进行操作,如果刚好执行到一个子节点,它的节点标记为rt,这时tree[rt].l == a && tree[rt].r == b 这时我们可以一步更新此时rt节点的sum[rt]的值,sum[rt] += c * (tree[rt].r - tree[rt].l + 1),注意关键的时刻来了,如果此时按照常规的线段树的update操作,这时候还应该更新rt子节点的sum[]值,而Lazy思想恰恰是暂时不更新rt子节点的sum[]值,到此就return,直到下次需要用到rt子节点的值的时候才去更新,这样避免许多可能无用的操作,从而节省时间 。

#define _CRT_SECURE_NO_DEPRECATE
#include<iostream>
#include<algorithm>
const int MAXN = 100000+10;
typedef long long LL;
using namespace std;
struct Tnode{
    int b, e;
    LL sum;     //当前区间和
    LL mark;   //延迟标记
};
Tnode tree[4*MAXN];
int n;
void Build(int v, int b, int e){
    tree[v].b = b, tree[v].e = e;
    tree[v].sum=tree[v].mark = 0;
    if (b < e){
        int mid = (b + e) >> 1;
        Build(2 * v + 1, b, mid);
        Build(2 * v + 2, mid + 1, e);
    }
}
void update(int v, int l, int r, LL value){
    if (l == tree[v].b&&r == tree[v].e){
        tree[v].mark += value;     //该区间每个数都要增加value,它的子区间可以先不更新(Lazy)
        return;          //直接返回了
    }
    tree[v].sum += value*(r - l + 1);   //将增加的值更新进去
    int mid = (tree[v].b + tree[v].e) >> 1;
    if (r <= mid)
        update(2 * v + 1, l, r, value);
    else if (l > mid)
        update(2 * v + 2, l, r, value);
    else{
        update(2 * v + 1, l, mid, value);
        update(2 * v + 2, mid + 1, r, value);
    }
}
LL Qurrey(int v, int l, int r){
    if (tree[v].b==l&&tree[v].e==r)
        return tree[v].sum+(r-l+1)*tree[v].mark;
    if (tree[v].mark != 0){  //之前欠的债现在要还了
        //如果当前区间mark不为0,则将它传递给子区间
        tree[2 * v + 1].mark += tree[v].mark;
        tree[2 * v + 2].mark += tree[v].mark;
        tree[v].sum += tree[v].mark*(tree[v].e-tree[v].b+1);
        tree[v].mark = 0;   
    }
    int mid = (tree[v].b + tree[v].e) >> 1;
    if (r <= mid)
        return Qurrey(2 * v + 1, l, r);
    else if (l > mid)
        return Qurrey(2 * v + 2, l, r);
    else
        return Qurrey(2 * v + 1, l, mid) + Qurrey(2 * v + 2, mid + 1, r);
        
}
int main(){
    long long x;
    int a, b,i,q;
    char ch;
    scanf("%d%d", &n, &q);
    Build(0, 1, n);
    for (i = 1; i <= n; i++){
        scanf("%lld", &x);
        update(0, i, i, x);
    }
    while (q--){
        cin >> ch;
        scanf("%d%d", &a, &b);
        if (ch == 'Q')
            printf("%lld
", Qurrey(0, a, b));
        else{
            scanf("%lld", &x);
            update(0, a, b, x);
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/td15980891505/p/5728089.html