1 条题解

  • 0
    @ 2025-6-14 10:41:50

    树状数组写法

    did_i 为原数组的差分数组,则 ai=j=1idja_i=\sum_{j=1}^i{d_j}

    那么对应的前缀和 $sum_i=\sum_{j=1}^i{a_j} = \sum_{j=1}^i\sum_{k=1}^j{d_k}$

    考虑每个 dkd_k 的贡献易得

    $sum_i = \sum_{k=1}^i{d_k\times (i-k+1)} = \sum_{k=1}^i{d_k\times (i+1)-d_k\times k} $

    整理可得 $sum_i = ((i+1)\times \sum_{k=1}^i{d_k}) - \sum_{k=1}^i{d_k\times k}$

    因此用两个树状数组分别维护差分数组 did_idi×id_i\times i 即可。

    前半部分,两个树状数组

    #include <bits/stdc++.h>
    #define int long long
    using namespace std;
    const int MAXN = 500000;
    int n, m;
    int a[MAXN + 5];
    int lowbit(int x)
    {
        return x & (-x);
    }
    // t[] 维护差分数组 d[i]
    int t[MAXN + 5];
    // 第x个数加k
    void update(int x, int k)
    {
        for (int i = x; i <= n; i += lowbit(i))
            t[i] += k;
    }
    // 返回前x个数的和
    int query(int x)
    {
        int res = 0;
        for (int i = x; i >= 1; i -= lowbit(i))
            res += t[i];
        return res;
    }
    // t2[] 维护 d[i]*i
    int t2[MAXN + 5];
    void update2(int x, int k)
    {
        for (int i = x; i <= n; i += lowbit(i))
            t2[i] += k;
    }
    int query2(int x)
    {
        int res = 0;
        for (int i = x; i >= 1; i -= lowbit(i))
            res += t2[i];
        return res;
    }
    

    重点:求前缀和 sumisum_i

    $sum_i = ((i+1)\times \sum_{k=1}^i{d_k}) - \sum_{k=1}^i{d_k\times k}$

    // 利用 t[] 和 t2[] 求 a[] 的前缀和
    int sum(int i)
    {
        int res = 0;
        res += (i + 1) * query(i);
        res -= query2(i);
        return res;
    }
    

    主函数

    signed main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);
        cin >> n >> m;
        for (int i = 1; i <= n; i++)
        {
            cin >> a[i];
            if (i == 1)
            {
                update(i, a[i]);
                update2(i, a[i] * i);
            }
            else
            {
                update(i, a[i] - a[i - 1]);
                update2(i, (a[i] - a[i - 1]) * i);
            }
        }
        while (m--)
        {
            int op, x, y, k;
            cin >> op;
            if (op == 1)
            {
                cin >> x >> y >> k; // a[x]~a[y] +=y
                update(x, k);
                update(y + 1, -k);
                update2(x, k * x);
                update2(y + 1, -k * (y + 1));
            }
            else
            {
                cin >> x >> y; // cout sum(a[x]~a[y])
                cout << sum(y) - sum(x - 1) << "\n";
            }
        }
        return 0;
    }
    
    • 1

    信息

    ID
    3616
    时间
    1000ms
    内存
    512MiB
    难度
    4
    标签
    递交数
    6
    已通过
    5
    上传者