zoukankan      html  css  js  c++  java
  • 线段树

    线段树 1:单点修改,区间查询

    代码:

    /* Segment Tree 1
     * Au: GG
     */
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <ctime>
    #include <iostream>
    #include <algorithm>
    #define ll long long
    using namespace std;
    
    const int N = 500005;
    
    int n, m, data[N];
    
    struct tree {
        int l, r;
        ll sum;
    } tr[N << 2]; // 四倍大小
    
    void build(int x, int y, int i) {
        tr[i].l = x, tr[i].r = y;
    
        if (x == y) tr[i].sum = data[x]; // 叶子节点直接赋值
        else {
            int mid = (x + y) >> 1;
            build(x, mid, i<<1); // 左子树
            build(mid + 1, y, i<<1|1); // 右子树
            tr[i].sum = tr[i<<1].sum + tr[i<<1|1].sum; // 回溯时维护区间和
        }
    }
    
    void update(int x, int val, int i) {
        if (tr[i].l == x && tr[i].r == x) // 找到了叶子
            tr[i].sum += val;
        else {
            int mid = (tr[i].l + tr[i].r) >> 1;
            if (x <= mid)
                update(x, val, i<<1);
            else if (x > mid)
                update(x, val, i<<1|1);
            tr[i].sum = tr[i<<1].sum + tr[i<<1|1].sum; // 回溯时维护区间和
        }
    }
    
    ll query(int x, int y, int i) {
        if (x <= tr[i].l && y >= tr[i].r) // 当前结点的区间完全被目标区间包含
            return tr[i].sum;
        else {
            int mid = (tr[i].l + tr[i].r) >> 1;
            if (x > mid) // 完全在右儿子
                return query(x, y, i<<1|1);
            else if (y <= mid) // 完全在左儿子
                return query(x, y, i<<1);
            else // 目标区间在左右都有分布
                return query(x, y, i<<1) + query(x, y, i<<1|1);
        }
    }
    
    int main() {
        scanf("%d", &n);
        scanf("%d", &m);
        for (int i = 1; i <= n; i++)
            scanf("%d", &data[i]);
        build(1, n, 1);
    
        while (m--) {
            int op, a, b;
            scanf("%d", &op);
            if (op == 1) { // 单点修改
                scanf("%d%d", &a, &b);
                update(a, b, 1);
            }
            else { // 区间求和
                scanf("%d%d", &a, &b);
                printf("%lld
    ", query(a, b, 1));
            }
        }
    
        return 0;
    }
    

    线段树 2:区间修改,区间查询

    代码:

    /* Segment Tree 2
     * Au: GG
     */
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <ctime>
    #include <iostream>
    #include <algorithm>
    #define ll long long
    using namespace std;
    
    const int N = 500005;
    
    int n, m, data[N];
    
    struct tree {
        int l, r;
        ll sum, lazy;
    } tr[N << 2]; // 四倍大小
    
    void build(int x, int y, int i) {
        tr[i].l = x, tr[i].r = y;
    
        if (x == y) tr[i].sum = data[x]; // 叶子节点直接赋值
        else {
            int mid = (x + y) >> 1;
            build(x, mid, i<<1); // 左子树
            build(mid + 1, y, i<<1|1); // 右子树
            tr[i].sum = tr[i<<1].sum + tr[i<<1|1].sum; // 回溯时维护区间和
        }
    }
    
    void push_down(int i, int m) {
    	if (tr[i].lazy) {
    		tr[i<<1].lazy += tr[i].lazy;
    		tr[i<<1|1].lazy += tr[i].lazy;
    		tr[i<<1].sum += tr[i].lazy * (m - (m >> 1));
    		tr[i<<1|1].sum += tr[i].lazy * (m >> 1);
    		tr[i].lazy = 0;
    	}
    }
    
    void update(int x, int y, int val, int i) {
        if (tr[i].l >= x && tr[i].r <= y) { // 目标区间完全被覆盖
            tr[i].lazy += val;
            tr[i].sum += val * (tr[i].r - tr[i].l + 1);
            return;
        }
        else {
        	push_down(i, tr[i].r - tr[i].l + 1); // 分解下传延迟信息
            int mid = (tr[i].l + tr[i].r) >> 1;
            if (y <= mid)
                update(x, y, val, i<<1);
            else if (x > mid)
                update(x, y, val, i<<1|1);
            else
            	update(x, y, val, i<<1|1), update(x, y, val, i<<1);
            tr[i].sum = tr[i<<1].sum + tr[i<<1|1].sum; // 回溯时维护区间和
        }
    }
    
    ll query(int x, int y, int i) {
        if (x <= tr[i].l && y >= tr[i].r) // 当前结点的区间完全被目标区间包含
            return tr[i].sum;
        else {
        	push_down(i, tr[i].r - tr[i].l + 1);
            int mid = (tr[i].l + tr[i].r) >> 1;
            if (x > mid)
                return query(x, y, i<<1|1);
            else if (y <= mid)
                return query(x, y, i<<1);
            else 
                return query(x, y, i<<1) + query(x, y, i<<1|1);
        }
    }
    
    int main() {
        scanf("%d", &n);
        scanf("%d", &m);
        for (int i = 1; i <= n; i++)
            scanf("%d", &data[i]);
        build(1, n, 1);
    
        while (m--) {
            int op, a, b, c;
            scanf("%d", &op);
            if (op == 1) { // 单点修改
                scanf("%d%d%d", &a, &b, &c);
                update(a, b, c, 1);
            }
            else { // 区间求和
                scanf("%d%d", &a, &b);
                printf("%lld
    ", query(a, b, 1));
            }
        }
    
        return 0;
    }
    

    Post author 作者: Grey
    Copyright Notice 版权说明: Except where otherwise noted, all content of this blog is licensed under a CC BY-NC-SA 4.0 International license. 除非另有说明,本博客上的所有文章均受 知识共享署名 - 非商业性使用 - 相同方式共享 4.0 国际许可协议 保护。
  • 相关阅读:
    HDU4529 郑厂长系列故事——N骑士问题 —— 状压DP
    POJ1185 炮兵阵地 —— 状压DP
    BZOJ1415 聪聪和可可 —— 期望 记忆化搜索
    TopCoder SRM420 Div1 RedIsGood —— 期望
    LightOJ
    LightOJ
    后缀数组小结
    URAL
    POJ3581 Sequence —— 后缀数组
    hdu 5269 ZYB loves Xor I
  • 原文地址:https://www.cnblogs.com/greyqz/p/8482433.html
Copyright © 2011-2022 走看看