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

【模板】树状数组 1

题目描述

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

  • 将某一个数加上 xxx

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

输入格式

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

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

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

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

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

输出格式

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

样例 #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≤81 \le n \le 81n81≤m≤101\le m \le 101m10
对于 70%70\%70% 的数据,1≤n,m≤1041\le n,m \le 10^41n,m104
对于 100%100\%100% 的数据,1≤n,m≤5×1051\le n,m \le 5\times 10^51n,m5×105

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

思路

树状数组模板题当然要用树状数组写啦。 首先,lowbitlowbitlowbit 为一个数的二进制表示中最右边的 111 所对应的 222 次幂的值。而树状数组其实是利用二进制表示的特性,用每一个节点来存储某一段区间的信息。虽然树状数组的节点不包含所有的区间,但是它可以对已存储的区间对应节点进行O(logN)O(logN)O(logN)次的加加减减的操作,使之可以任意表示一个区间。也就是说,树状数组可以将数量庞大的所有区间用数量较小的节点区间以每次O(logN)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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值