zoukankan      html  css  js  c++  java
  • [算法]树状数组

    前言

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

    单点修改,区间查询

    就是一个优化过的前缀和,使查询和修改协调为(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 ]

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

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

    于是

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

    最后我们愉快的差分维护两个树状数组,
    一个维护(d_i),另一个维护(d_i imes 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
    ", query(l, r));
                    break;
                default:
                    puts("Invalid Command!");
                    break;
            }
        }
        return 0;
    }
    
  • 相关阅读:
    P2380狗哥采矿(状态不易设计)
    P2320鬼谷子的钱袋(分治)
    树型背包(模板)
    Tarjan缩点割点(模板)
    最短路记录路径(模板)
    P1790 矩形分割(隐含的电风扇)
    P1725 琪露诺(单调队列优化)
    BZOJ3236: [Ahoi2013]作业
    BZOJ3809: Gty的二逼妹子序列
    BZOJ2190: [SDOI2008]仪仗队
  • 原文地址:https://www.cnblogs.com/linzhengmin/p/11073801.html
Copyright © 2011-2022 走看看