跳转至

树状数组

2025-03-31

树状数组其实已经是比较高级的东西了吧,而且代码也比较短。其实我并不很懂里面的原理,只会背个模板。。

为什么ST表模板是黄,树状数组两个都是绿。。。

其实记得代码就行吧。如果没有时间。

常用操作主要是 单点修改,区间查询区间修改,单点查询。单次修改查询复杂度为 \(O(\log n)\)

单点修改,区间查询

P3374 【模板】树状数组 1

注意 add 时,可以判一下 \(i\) 不为 \(0\) ,否则哪天没准死循环。。。ask 也可以尽量写成 \(i > 0\) ,这样碰到不小心有负数过来也没事。

using ll = long long;
struct Fenwick
{
    vector<ll> b;
    Fenwick(int n)
    {
        b = vector<ll>(n + 1);
    }
    int lowbit(int x) { return (x) & (-x); }
    void add(int i, int x)
    {
        while (i && i < b.size())
        {
            b[i] += x;
            i += lowbit(i);
        }
    }
    ll ask(int i)
    {
        ll res = 0;
        while (i > 0)
        {
            res += b[i];
            i -= lowbit(i);
        }
        return res;
    }
};
void ChatGptDeepSeek()
{
    int n, m;
    cin >> n >> m;
    vector<int> a(n + 1);
    Fenwick C(n + 1);
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        C.add(i, a[i]);
    }
    while (m--)
    {
        int op, x, y;
        cin >> op >> x >> y;
        if (op == 1)
            C.add(x, y);
        else
            cout << C.ask(y) - C.ask(x - 1) << '\n';
    }
}

区间修改,单点查询

P3368 【模板】树状数组 2

其实是不是并不一定能区间修改。。区间加可以。如果能想到用差分,那就是普通的模板了。

前面内容相同,这里就省略了。

void ChatGptDeepSeek()
{
    int n, m;
    cin >> n >> m;
    vector<int> a(n + 1);
    Fenwick C(n + 1);
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    while (m--)
    {
        int op;
        cin >> op;
        if (op == 1)
        {
            int x, y, k;
            cin >> x >> y >> k;
            C.add(x, k);
            C.add(y + 1, -k);
        }
        else
        {
            int x;
            cin >> x;
            cout << C.ask(x) + a[x] << '\n';
        }
    }
}

P5057 [CQOI2006] 简单题

跟上面那题差不多。。但我没看出来,于是拿线段树做了,发现原来树状数组做这么简单。。虽然也没有写多久。。