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 国际许可协议 保护。
  • 相关阅读:
    centos7 python3.5中引入sqlite3
    转载nginx+uwsgi+django
    浮点数计算精度丢失问题#W01
    五大JavaScript 自动化测试框架
    deepin 安装Samba并设置为开机启动
    搭建macaca android环境
    open-MAT 安装部署
    基于Jmeter BackEnd+InfluxDB+Grafana实现性能指标实时可视监控
    使用开源libimobiledevice查看iphone信息
    Java 开发者必备测试框架
  • 原文地址:https://www.cnblogs.com/greyqz/p/8482433.html
Copyright © 2011-2022 走看看