[算法]树状数组

前言

相信大家都会树状数组的"单点修改,区间查询"或者"区间修改,单点查询",博主就不细讲了。
但是博主今天发现了一个神奇的算法(博主太菜),它可以使用树状数组维护"区间修改,区间查询"。

单点修改,区间查询

就是一个优化过的前缀和,使查询和修改协调为\(\Theta(log_2n)\)

代码

namespace FenTree{
	#define lowbit(x) (x&-x)
	#define MAXN 100005
	int BIT[MAXN];
	int query(int i){
		int res = 0;
		for ( ; i; i -= lowbit(i)) res += BIT[i]; return res;
	}
	void add(int i, int val){
		for ( ; i <= n; i += lowbit(i)) BIT[i] += val;
	}
	#undef MAXN
	#undef lowbit
};

区间修改,单点查询

将上面的树状数组进行差分,就珂以了

区间修改,区间查询

算法详解

设原数组\(a\)从下标一开始,长度为\(n\)\(a_i-a_{i-1}\)记为\(\delta_i\),我们规定\(a_0=0\)
那么

\[a_i=\sum_{j=1}^i{\delta}_i \]

上式求和时两两抵消,易证。
所以,若\(x\in[1,n]\)

\[\sum_{i=1}^xa_i=\sum_{i=1}^x\sum_{j=1}^i{\delta}_j=\sum_{i=1}^x(x-i+1)\times{\delta}_i \]

于是

\[\sum_{i=1}^xa_i=(x+1)\sum_{i=1}^x{\delta}_i-\sum_{i=1}^x{\delta}_i \times i \]

最后我们愉快的差分维护两个树状数组,
一个维护\(d_i\),另一个维护\(d_i \times i\)

代码

namespace FenWick{
    #define lowbit(x) (x&(-x))
    #define ll long long
    #define MAXN 1000005
    int n; 
    ll d1[MAXN] , d2[MAXN];
    void modifySuffix(int x, ll val){
        for (int i = x; i <= n; i += lowbit(i))
            d1[i] += val, d2[i] += val * x;
    }
    inline void modify(int x, int y, ll val){
        modifySuffix(x, val), modifySuffix(y + 1, -val);
    }
    ll queryPrefix(int x){
        ll res = 0;
        for (int i = x; i; i -= lowbit(i))
            res += (x + 1) * d1[i] - d2[i];
        return res;
    }
    inline ll query(int x, int y){
        return (queryPrefix(y) - queryPrefix(x - 1));
    }
};

练习

[LOJ132]树状数组 3 :区间修改,区间查询

#include <cstdio>

namespace FenWick{
    #define lowbit(x) (x&(-x))
    #define ll long long
    #define MAXN 1000005
    int n; 
    ll d1[MAXN] , d2[MAXN];
    void modifySuffix(int x, ll val){
        for (int i = x; i <= n; i += lowbit(i))
            d1[i] += val, d2[i] += val * x;
    }
    inline void modify(int x, int y, ll val){
        modifySuffix(x, val), modifySuffix(y + 1, -val);
    }
    ll queryPrefix(int x){
        ll res = 0;
        for (int i = x; i; i -= lowbit(i))
            res += (x + 1) * d1[i] - d2[i];
        return res;
    }
    inline ll query(int x, int y){
        return (queryPrefix(y) - queryPrefix(x - 1));
    }
};

using namespace FenWick;

ll read(){
    ll x = 0; int zf = 1; char ch = ' ';
    while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
    if (ch == '-') zf = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); return x * zf;
}

int main(){
    n = read(); int q = read();
    for (int i = 1; i <= n; ++i)
        modify(i, i, read());
    while (q--){
        int op = read(), l = read(), r = read(), x;
        switch(op){
            case 1:
                x = read();
                modify(l, r, x);
                break;
            case 2:
                printf("%lld\n", query(l, r));
                break;
            default:
                puts("Invalid Command!");
                break;
        }
    }
    return 0;
}
posted @ 2019-06-23 19:08  LinZhengmin  阅读(202)  评论(0编辑  收藏  举报

Contact with me