洛谷 P3374 [模板] 树状数组 1

【模板】树状数组 1

题目描述

如题,已知一个数列,你需要进行下面两种操作:

  • 将某一个数加上 x x x

  • 求出某区间每一个数的和

输入格式

第一行包含两个正整数 n , m n,m n,m,分别表示该数列数字的个数和操作的总个数。

第二行包含 n n n 个用空格分隔的整数,其中第 i i i 个数字表示数列第 i i i 项的初始值。

接下来 m m m 行每行包含 3 3 3 个整数,表示一个操作,具体如下:

  • 1 x k 含义:将第 x x x 个数加上 k k k

  • 2 x y 含义:输出区间 [ x , y ] [x,y] [x,y] 内每个数的和

输出格式

输出包含若干行整数,即为所有操作 2 2 2 的结果。

样例 #1

样例输入 #1

5 5
1 5 4 2 3
1 1 3
2 2 5
1 3 -1
1 4 2
2 1 4

样例输出 #1

14
16

提示

【数据范围】

对于 30 % 30\% 30% 的数据, 1 ≤ n ≤ 8 1 \le n \le 8 1n8 1 ≤ m ≤ 10 1\le m \le 10 1m10
对于 70 % 70\% 70% 的数据, 1 ≤ n , m ≤ 1 0 4 1\le n,m \le 10^4 1n,m104
对于 100 % 100\% 100% 的数据, 1 ≤ n , m ≤ 5 × 1 0 5 1\le n,m \le 5\times 10^5 1n,m5×105

数据保证对于任意时刻, a a a 的任意子区间(包括长度为 1 1 1 n n n 的子区间)和均在 [ − 2 31 , 2 31 ) [-2^{31}, 2^{31}) [231,231) 范围内。

思路

树状数组模板题当然要用树状数组写啦。 首先, l o w b i t lowbit lowbit 为一个数的二进制表示中最右边的 1 1 1 所对应的 2 2 2 次幂的值。而树状数组其实是利用二进制表示的特性,用每一个节点来存储某一段区间的信息。虽然树状数组的节点不包含所有的区间,但是它可以对已存储的区间对应节点进行 O ( l o g N ) O(logN) O(logN)次的加加减减的操作,使之可以任意表示一个区间。也就是说,树状数组可以将数量庞大的所有区间用数量较小的节点区间以每次 O ( l o g N ) O(logN) O(logN)的复杂度来全部表示。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 5e5 + 6;

int n, m;

int s[maxn]; // 树状数组

int lowbit(int x) // 获取低位2次幂数
{
    return x & -x;
}

void change(int x, int k) // 单点修改
{
    while (x <= n)
    {
        s[x] += k;
        x += lowbit(x);
    }
}

int query(int x) // 前缀和查询
{
    int res = 0;
    while (x)
    {
        res += s[x];
        x -= lowbit(x);
    }
    return res;
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);

    cin >> n >> m;

    int x, y, k, op;

    for (int i = 1; i <= n; i++)
    {
        cin >> k;
        change(i, k);
    }

    while (m--)
    {
        cin >> op;
        if (op == 1)
        {
            cin >> x >> k;
            change(x, k);
        }
        else
        {
            cin >> x >> y;
            cout << query(y) - query(x - 1) << '\n'; // 区间答案即为[0,y]的前缀和减去[0,x-1]的前缀和
        }
    }

    return 0;
}
  • 21
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值