链接 | zkw线段树

[数据结构]走近Zkw线段树(一)

[数据结构]走近Zkw线段树(二)

线段树的扩展之浅谈zkw线段树

#include<bits/stdc++.h>
#define lc(x) (x<<1)
#define rc(x) (x<<1|1)
using namespace std;
const int maxn = 100005;
int max(int a, int b) { return a>b ? a : b; }

long long tr[maxn<<2];
int M, N;

void maintain(int p) { tr[p] = tr[lc(p)] + tr[rc(p)]; }

void build() {
    for(M=1; M<=N; M++);
    for(int i=M+1; i<=M+N; i++) scanf("%lld", &tr[i]);
    for(int i=M-1; i; i--) maintain(i);
}

void single_update(int pos, int v) {
    pos += M;
    tr[pos] += v;
    for(pos>>=1; pos; pos>>=1) maintain(pos);
}

long long static_RMQ(int l, int r) {
    long long ans=0;
    for(l+=M-1,r+=M+1; l^r^1; l>>=1, r>>=1) {
        if(!(l&1)) ans += tr[l^1];
        if(r&1) ans += tr[r^1];
    }
    return ans;
}

int main() {
    int m;
    scanf("%d%d", &N, &m);
    build();
    while(m--) {
        int op, i, j;
        scanf("%d%d%d", &op, &i, &j);
        if(op == 1) update(i, j);
        else printf("%lld
", RMQ(i, j));
    }
    return 0;
}
单点更新

-

#include<bits/stdc++.h>
#define lc(x) (x<<1)
#define rc(x) (x<<1|1)
using namespace std;
const int maxn = 100005, maxm = maxn<<2;
typedef long long LL;
int max(int a, int b) { return a>b ? a : b; }

LL tr[maxm];
int M, N;
int L[maxm], R[maxm];
LL down[maxm];

void maintain(int p) { tr[p] = tr[lc(p)] + tr[rc(p)]; }

void build() {
    for(M=1; M<=N; M++);
    for(int i=M+1; i<=M+N; i++) {
        scanf("%lld", &tr[i]);
        L[i] = R[i] = i-M;
    }
    for(int i=M-1; i; i--) {
        maintain(i);
        L[i] = L[lc(i)];
        R[i] = R[rc(i)];
    }
}

//区间和式pushDown 
void pushDown(int p) {
    if(down[p] && p<M) { // 不是叶节点 
        down[lc(p)] += down[p]; down[rc(p)] += down[p];
        tr[lc(p)] += (R[lc(p)] - L[lc(p)] + 1) * down[p];
        tr[rc(p)] += (R[rc(p)] - L[rc(p)] + 1) * down[p];
        down[p] = 0;
    }
}

//从叶节点往回走到根,再自顶向下下推标记 
void applyTag(int p) {
    stack<int> s;
    while(p) s.push(p), p>>=1;
    while(!s.empty()) pushDown(s.top()), s.pop();
}

void range_update(int l, int r, int v) {
    bool vl, vr; vl = vr = false;
    int x;
    int sl=0, sr=0;
    for(l += M-1, r += M+1; l^r^1; l>>=1, r>>=1) {
        if(~l&1) {
            x = l^1; // 点l^1被完整包含在更新的区间里 
            if(!vl) {
                sl = x; // 记录最底层被完整包含的区间 
                applyTag(x), vl = true;
            }
            down[x] += v;
            tr[x] += (R[x] - L[x] + 1) * v;
        }
        if(r&1) {
            x = r^1; // 点r^1同理 
            if(!vr) {
                sr = x;
                applyTag(x), vr = true;
            }
            down[x] += v;
            tr[x] += (R[x] - L[x] + 1) * v;
        }
    }
    for(sl>>=1; sl; sl>>=1) maintain(sl); //从最底层被完整包含的区间向上更新维护 
    for(sr>>=1; sr; sr>>=1) maintain(sr);
}

LL range_query(int l, int r) {
    bool vl, vr; vl = vr = false;
    LL ans=0;
    for(l += M-1, r += M+1; l^r^1; l>>=1, r>>=1) {
        if(~l&1) {
            if(!vl) applyTag(l^1), vl = true;
            ans += tr[l^1];
        }
        if(r&1) {
            if(!vr) applyTag(r^1), vr = true;
            ans += tr[r^1];
        }
    }
    return ans;
}

int main() {
    int m;
    scanf("%d%d", &N, &m);
    build();
    while(m--) {
        int op, a, b, v;
        scanf("%d%d%d", &op, &a, &b);
        if(op == 1) scanf("%d", &v), range_update(a, b, v);
        else printf("%lld
", range_query(a, b));
    }
    return 0;
}
区间和更新

-

原文地址:https://www.cnblogs.com/de-compass/p/12054884.html