• 线段树 (模板)


    功能

    (log_2n)时间复杂度对区间进行加减乘求和等等操作的数据结构。

    实现

    主要参考的是oi_wiki教程。
    记录一下板子(即HDU1166 - 敌兵布阵的代码)

    注意事项

    1. 开4倍空间,再大点更好。
    2. 叶结点不要pushdown,否则可能会越界(因为只开了4倍空间)
    //L,R均代表待处理的区间。
    //lef,rig均代表范围。
    //单点更新(覆盖),区间求和
    #include <cstdio>
    #include <iostream>
    #include <cstring>
    
    using namespace std;
    
    typedef long long ll;
    
    const ll maxn = 50001;
    
    ll sum[maxn << 2];
    ll lazy[maxn << 2];
    
    void pushup(int rt) {
        sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
    }
    
    void pushdown(int rt, int len) {
        if(lazy[rt]) {
            lazy[rt << 1] += lazy[rt];
            lazy[rt << 1 | 1] += lazy[rt];
            sum[rt << 1] += lazy[rt << 1] * (len - (len >> 1));
            sum[rt << 1 | 1] += lazy[rt << 1 | 1] * (len >> 1);
            lazy[rt] = 0;
        }
    }
    
    void update(int L, int R, int lef, int rig, int rt, ll val) {
        if(lef >= L && rig <= R) {
            sum[rt] += val * (rig - lef + 1);
            lazy[rt] += val;
            return ;
        }
        pushdown(rt, rig - lef + 1);
        int mid = (lef + rig) / 2;
        if(L <= mid) update(L, R, lef, mid, rt << 1, val);
        if(R > mid) update(L, R, mid + 1, rig, rt << 1 | 1, val);
        pushup(rt);
    }
    
    void build(int lef, int rig, int rt) {
        if(lef > rig) return ;
        lazy[rt] = 0;
        if(lef == rig) {
            ll tmp;
            scanf("%lld", &tmp);
            sum[rt] = tmp;
            return ;
        }
        int mid = (lef + rig) / 2;
        build(lef, mid, rt << 1);
        build(mid + 1, rig, rt << 1 | 1);
        pushup(rt);
    }
    
    ll query(int L, int R, int lef, int rig, int rt) {
        if(lef >= L && rig <= R) return sum[rt];
        pushdown(rt, rig - lef + 1);
        int mid = (lef + rig) / 2;
        ll res = 0;
        if(L <= mid) res += query(L, R, lef, mid, rt << 1);
        if(R > mid) res += query(L, R, mid + 1, rig, rt << 1 | 1);
        return res;
    }
    
    
    int main() {
        int T = 0;
        char q[10];
        scanf("%d", &T);
        for(int cases = 1; cases <= T; cases++) {
            printf("Case %d:
    ", cases);
            int n;
            scanf("%d", &n);
            build(1, n, 1);
            while(1) {
                scanf("%s", q);
                if(!strcmp(q, "Add")) {
                    int pos;
                    ll val;
                    scanf("%d%lld", &pos, &val);
                    update(pos, pos, 1, n, 1, val);
                }
                else if(!strcmp(q, "Sub")) {
                    int pos;
                    ll val;
                    scanf("%d%lld", &pos, &val);
                    update(pos, pos, 1, n, 1, -val);
                }
                else if(!strcmp(q, "Query")) {
                    int L, R;
                    scanf("%d%d", &L, &R);
                    printf("%lld
    ", query(L, R, 1, n, 1));
                }
                else if(!strcmp(q, "End")) break;
            }
        }
    }
    

    其它

    对于大范围的区间操作,可以用离散化的技巧。但是这主要处理以后线段树就不支持在线操作了。
    似乎有一种动态开点的方法可以解决这问题,有时间补上。

  • 相关阅读:
    记账本开发记录——第十三天(2020.1.31)
    《构建之法——现代软件工程》读书笔记(二)
    记账本开发记录——第十二天(2020.1.30)
    记账本开发记录——第十一天(2020.1.29)
    记账本开发记录——第十天(2020.1.28)
    记账本开发记录——第九天(2020.1.27)
    记账本开发记录——第八天(2020.1.26)
    记账本开发记录——第七天(2020.1.24)
    记账本开发记录——第六天(2020.1.23)
    记账本开发记录——第五天(2020.1.22)
  • 原文地址:https://www.cnblogs.com/limil/p/12698239.html
Copyright © 2020-2023  润新知