• P3368 【模板】树状数组 2


    题目传送门

    • 知识点:区间修改,单点查询

    通过 差分(就是记录数组中每个元素与前一个元素的差),可以把这个问题转化为问题1。

    查询
    设原数组为\(a[i]\), 设数组\(d[i]=a[i]-a[i-1](a[0]=0)\),则\(a[i]=\sum_{j=1}^{i}d[j]\),可以通过求\(d[i]\)的前缀和查询。

    修改
    当给区间\([l,r]\)加上\(x\)的时候,\(a[l]\)与前一个元素 \(a[l-1]\)的差增加了\(x\)\(a[r+1]\)\(a[r]\)的差减少了\(x\)。根据\(d[i]\)数组的定义,只需给\(a[l]\)加上\(x\), 给 \(a[r+1]\)减去\(x\)即可。

    #include <bits/stdc++.h>
    using namespace std;
    #define lowbit(x) (x & -x)
    
    const int N = 5e5 + 5;
    int a[N], t[N]; // a是原数组。t是差分数组,用树状数组维护。
    
    int n, m;
    
    inline void add(int x, int v) { //这个函数用来在树状数组中直接修改
        while (x <= n) t[x] += v, x += x & -x;
    }
    
    //所谓区间修改,本质是通过差分,对一头一尾进行两次单点修改
    void range_add(int l, int r, int v) { //给区间[l, r]加上x
        add(l, v), add(r + 1, -v);
    }
    
    int query(int x) { //单点查询
        int res = 0;
        while (x) res += t[x], x -= lowbit(x);
        return res;
    }
    
    int main() {
        scanf("%d %d", &n, &m);
    
        //原数组
        for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    
        int op, l, r, v, k;
        while (m--) {
            scanf("%d", &op);
            if (op == 1) {
                scanf("%d %d %d", &l, &r, &v);
                range_add(l, r, v); //区间修改
            } else {
                scanf("%d", &k);
                printf("%d\n", a[k] + query(k)); //求某点的值
            }
        }
        return 0;
    }
    
    
  • 相关阅读:
    MYSQL中replace into的用法以及与inset into的区别
    怎么安装phpcms?PHPCMS V9安装图文教程
    Yii 框架生成缩略图
    怎么让普通用户使用root权限执行用户命令
    自学Linux命令的四种方法
    最完整PHP.INI中文版
    前端chrome浏览器调试
    phpstorm快捷键记录
    客户关系管理
    Subquery returns more than 1 row
  • 原文地址:https://www.cnblogs.com/littlehb/p/16224866.html
Copyright © 2020-2023  润新知