1 条题解

  • 1
    @ 2025-2-24 12:58:19
    #include<bits/stdc++.h>
    using namespace std;
    
    // 定义数组的最大长度
    const int N = 200005;
    // 存储原始数组
    long long a[N];
    // 记录每一块的增加值(懒标记),用于延迟更新块内元素的值
    long long bval[N]; 
    // 记录每一块的总和,不包含 bval 中的增加值
    long long bsum[N]; 
    // 数组的长度
    int n; 
    // 操作的数量
    int m; 
    // 块的大小
    int bsize; 
    
    // 修改操作函数,用于将区间 [l, r] 内的所有值增加 val
    void modify(int l, int r, int val) {
        // 计算区间左端点 l 所在的块编号
        int li = ceil(1.0 * l / bsize);
        // 计算区间右端点 r 所在的块编号
        int ri = ceil(1.0 * r / bsize);
        // 遍历包含在区间 [l, r] 内的所有块
        for (int j = li; j <= ri; j++) {
            // 计算当前块的左端点
            int ll = (j - 1) * bsize + 1;
            // 计算当前块的右端点,不能超过数组的最大长度
            int rr = min(j * bsize, n);
            // 如果当前块完全包含在区间 [l, r] 内
            if (l <= ll && rr <= r) {
                // 直接将该块的增加值 bval[j] 增加 val,不更新块内每个元素的值
                bval[j] += val;
            } else {
                // 如果当前块部分包含在区间 [l, r] 内
                // 遍历当前块内的所有元素
                for (int k = ll; k <= rr; k++) {
                    // 如果当前元素在区间 [l, r] 内
                    if (l <= k && k <= r) {
                        // 将该元素的值增加 val
                        a[k] += val;
                        // 更新该块的总和 bsum[j]
                        bsum[j] += val;
                    }
                }
            }
        }
    }
    
    // 查询操作函数,用于计算区间 [l, r] 内所有元素的和
    long long query(int l, int r) {
        // 计算区间左端点 l 所在的块编号
        int li = ceil(1.0 * l / bsize);
        // 计算区间右端点 r 所在的块编号
        int ri = ceil(1.0 * r / bsize);
        // 初始化查询结果为 0
        long long ans = 0;
        // 遍历包含在区间 [l, r] 内的所有块
        for (int j = li; j <= ri; j++) {
            // 计算当前块的左端点
            int ll = (j - 1) * bsize + 1;
            // 计算当前块的右端点,不能超过数组的最大长度
            int rr = min(j * bsize, n);
            // 如果当前块完全包含在区间 [l, r] 内
            if (l <= ll && rr <= r) {
                // 将该块的总和 bsum[j] 加上该块的增加值(bval[j] 乘以块内元素的数量)累加到 ans 中
                ans += bsum[j] + bval[j] * (rr - ll + 1);
            } else {
                // 如果当前块部分包含在区间 [l, r] 内
                // 遍历当前块内的所有元素
                for (int k = ll; k <= rr; k++) {
                    // 如果当前元素在区间 [l, r] 内
                    if (l <= k && k <= r) {
                        // 将该元素的值加上该块的增加值累加到 ans 中
                        ans += bval[j] + a[k];
                    }
                }
            }
        }
        return ans;
    }
    
    int main() {
        // 读取数组的长度 n 和操作的数量 m
        cin >> n >> m;
        // 计算块的大小,通常取 sqrt(n)
        bsize = floor(sqrt(n));
    
        // 初始化数组和块的总和
        for (int i = 1; i <= n; i++) {
            // 读取数组的第 i 个元素
            cin >> a[i];
            // 将该元素累加到其所属块的总和 bsum 中
            bsum[(int)ceil(1.0 * i / bsize)] += a[i];
        }
    
        // 处理 m 次操作
        for (int i = 1; i <= m; i++) {
            // 操作类型(0 表示修改操作,1 表示查询操作)
            int op; 
            // 区间的左端点
            int l; 
            // 区间的右端点
            int r; 
            // 读取操作类型、区间左端点和区间右端点
            cin >> op >> l >> r;
            if (op == 0) {
                // 如果是修改操作
                // 要增加的值
                int val; 
                // 读取要增加的值
                cin >> val;
                // 调用 modify 函数进行修改操作
                modify(l, r, val);
            } else {
                // 如果是查询操作
                // 调用 query 函数进行查询操作,并输出结果
                cout << query(l, r) << endl;
            }
        }
    
        return 0;
    }
    
    

    信息

    ID
    2048
    时间
    1000ms
    内存
    256MiB
    难度
    6
    标签
    递交数
    30
    已通过
    10
    上传者