• AcWing 242. 一个简单的整数问题


    \(AcWing\) \(242\). 一个简单的整数问题

    一、题目描述

    给定长度为 \(N\) 的数列 \(A\),然后输入 \(M\) 行操作指令。

    第一类指令形如 C l r d,表示把数列中第 \(l∼r\) 个数都加 \(d\)

    第二类指令形如 Q x,表示询问数列中第 \(x\) 个数的值。

    对于每个询问,输出一个整数表示答案。

    输入格式
    第一行包含两个整数 \(N\)\(M\)

    第二行包含 \(N\) 个整数 \(A[i]\)

    接下来 \(M\) 行表示 \(M\) 条指令,每条指令的格式如题目描述所示。

    输出格式
    对于每个询问,输出一个整数表示答案。

    每个答案占一行。

    二、算法分析

    树状数组 + 差分

    树状数组主要解决的是

    1、a[x] += c (单点修改)
    2、求a[L ~ R] (前缀和)

    总结:单点加,区间求和

    本题要求求的是

    1、a[L ~ R] += c
    2、求a[x]

    因为 前缀和差分 是一种逆运算,因此本题将原数组a[] 转换 差分数组b[],就变成了树状数组的模型

    • a[L ~ R] += c 等价于 b[L] += c,b[R + 1] -= c
    • a[x] 等价于b[1 ~ x]前缀和

    总结:区间加,单点求和

    注意:在求前缀和时,要特别注意数据范围,防止爆\(int\)

    三、实现代码

    #include <cstdio>
    
    using namespace std;
    typedef long long LL;
    const int N = 100010;
    
    //快读
    inline int read() {
        int x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' || ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9') {
            x = (x << 3) + (x << 1) + (ch ^ 48);
            ch = getchar();
        }
        return x * f;
    }
    
    int n, m;
    int a[N];
    
    //注意下这里与标准模板的不同,因为求和可能会超过int上限,需要开long long
    // t[i]表示树状数组i结点覆盖的范围和
    LL t[N];
    
    //返回非负整数x在二进制表示下最低位1及其后面的0构成的数值
    int lowbit(int x) {
        return x & -x;
    }
    //将序列中第x个数加上k
    void add(int x, int k) {
        for (int i = x; i <= n; i += lowbit(i)) t[i] += k;
    }
    //查询序列前x个数的和
    LL sum(int x) {
        int sum = 0;
        for (int i = x; i; i -= lowbit(i)) sum += t[i];
        return sum;
    }
    
    int main() {
        n = read(), m = read();
        for (int i = 1; i <= n; i++) a[i] = read();
    
        //树状数组初始化,保存差分值
        for (int i = 1; i <= n; i++) add(i, a[i] - a[i - 1]);
    
        while (m--) {
            char op[2]; //向yxc老师学习,向yxc老师致敬
            scanf("%s", op);
    
            if (op[0] == 'C') { //修改
                int l = read(), r = read(), d = read();
                //差分,在l处加上d,在r+1位置减去d
                add(l, d), add(r + 1, -d);
            } else {
                int l = read();
                printf("%lld\n", sum(l)); //求前缀和
            }
        }
        return 0;
    }
    
  • 相关阅读:
    金融系列7《动态数据认证》
    PHP异常处理详解
    C语言中的宏定义
    PHP SOCKET编程
    yii实现级联下拉菜单
    AR的一些常见的操作
    IP地址的三种表示格式及在Socket编程中的应用
    时间管理
    socket阻塞与非阻塞,同步与异步、I/O模型
    程序人生 PHP工程师
  • 原文地址:https://www.cnblogs.com/littlehb/p/16141314.html
Copyright © 2020-2023  润新知