树状数组——在高阶前缀和上的应用

HDU中超第五场打完后补题,被一个高阶前缀和折磨了两天
记录一下想法

树状数组——高阶前缀和

首先强化一下概念:树状数组的基本(根本)操作是单点修改,单点查询前缀和

通过对前缀和做小学减法我们做到了区间查询

现在要求对 \(a\)​​ 数组做单点修改,查询 \(a\)​​ 数组的二维前缀和

\(b,c\) 两数组分别为一阶、二阶前缀和

\[\begin{align} b_i &= \sum_1^i a_i,\quad c_i = \sum_1^ib_i\\ c_i &= ia_1 + (i-1)a_2+...+2a_{i-1} + a_i\\ &= i(a_1+a_2+...+a_i) - [(i-1)a_i + (i-2)a_{i-1}+....+a2+0] \end{align} \]

这样就将一个二阶前缀和问题转化成了两个一阶前缀和问题

用两个树状数组,分别处理 \(a_i\)​​​ ,\({(i-1)a_i}\)​​ 这两个序列即可

struct BitTree{//4行树状数组
    ll t[2*maxn];
    ll lb(int x) {return x&-x;}
    void add(int p, ll ad){for(int i=p;i<=n;i+=lb(i)) t[i]+=ad;}
    ll sum(int p){ return p?t[p] + sum(p-lb(p)):0;}
};

struct BitTree2{//二阶前缀和的树状数组
    BitTree bt1, bt2;
    void add(int p, ll ad){
        bt1.add(p, ad);
        bt2.add(p, ad * (p-1));
    }
    ll sum(int p){
        return bt1.sum(p) * p - bt2.sum(p);
    }
};

练习(模板题)

线段树最基础的模板题,区间修改区间查询,可以用二阶前缀和的树状数组做

具体而言,建立差分数组 \(d\)​ ,区间修改可以改为在 \(d\)​ 上的单点修改,那么区间查询就相当于查询 \(d\)​ 的二阶前缀和

BitTree2 bt;
ll d[maxn], n, m;

void solve(){
    cin >> n >> m;
    for(int i=1;i<=n;i++){
        cin >> d[i];
        bt.add(i, d[i]);
        bt.add(i+1, -d[i]);
    }
    for(int i=1;i<=m;i++){
        int opt,x,y,k;
        cin >> opt >> x >> y;
        if(opt == 1){
            cin >> k;
            bt.add(x, k);
            bt.add(y+1, -k);
        }else{
            cout << bt.sum(y) - bt.sum(x-1) << '\n';
        }
    }
}

更高阶呢?

以三阶前缀和为例

\[\begin{align} b_i &= \sum_1^i a_i, \quad c_i = \sum_1^ib_i, \quad d_i = \sum_1^ic_i \\ d_k &= \frac{k(1+k)}{2}a_1 + \frac{(k-1)k}{2}a_2+...+\frac{(2+k-i)*(1+k-i)}{2}a_i+...+\frac{3}{2}a_{k-1} + a_k \\ &= \frac{(k+1)(k+2)}{2}(a_1+...a_k)-\frac{2k+3}{2}(a_1+2a_2+...+ka_k)+\frac{1}{2}(a_1+4a_2+...+k^2a_k) \end{align} \]

推方程的时候,对于一般项 \(\frac{(2+k-i)*(1+k-i)}{2}a_i\)​​,要注意把 \(k\)\(i\) ​分开,目的是使某个\(f(i)a_i\) 形式的东西独立出来,方便单独用树状数组维护。

这里的过程是:

\[\frac{(2+k-i)*(1+k-i)}{2}a_i = \frac{(k+1)(k+2)}{2}a_i-\frac{2k+3}{2}ia_i+\frac{1}{2}i^2a_i \]

由此也成功转化成三个一阶前缀和问题

如果继续推下去,会发现 \(n\) 个树状数组就可以解决 \(n\) 阶前缀和问题

练习题(比赛原题)

三阶前缀和

题解见自己写的 2021暑假 HDU中超 第五场 1009

posted @ 2021-08-04 20:03  lx_tyin  阅读(484)  评论(0编辑  收藏  举报