# BIT 與 Polynomial Queries 的關聯性
## 前言
這篇文章的目的是要解釋如何使用Fenwick Tree(下稱BIT)來處理在線的Polynomial Queries(如下題),以及它的推導過程。
## 先備條件
1. 熟悉前綴和、差分、BIT的使用方法。
2. 不害怕數學抽象符號。
## 題目
來源:[zerojudge f992](https://zerojudge.tw/ShowProblem?problemid=f992)
簡易題敘:
> 給定 $n, k, q$ 與初始陣列 $a_1~a_n$ ,請執行 $q$ 次在線操作,操作皆為以下兩種之一:
> 1.給定 $l, r$ ,對於所有的 $l\leq i\leq r$ ,使 $a_i$ 增加 ${(i-l+1)}^k$ 。
> $~~~$( $a_l$ 增加 $1^k$ 、 $a_{l+1}$ 增加 $2^k$ 、…、 $a_r$ 增加 ${(r-l+1)}^k$ )
> 2.給定 $l, r$ ,輸出 $[l, r]$ 的區間和(對質數 ${10}^6+3$ 取模)。
> 值域:$1\leq n, q\leq{10}^5, 0 \leq k\leq 3, 1\leq a_i\leq{10}^9$
>
## 數學定義
為了方便,我們先假設一些代號。
定義 $A(0)$ 為原陣列, $A(0)_i$ 為原陣列的第 $i$ 項。
定義 $A(x)$ 為原陣列做 $x$ 次前綴和操作之後,所得到的新陣列,
而 $A(-x)$ 則為原陣列做 $x$ 次差分操作之後,所得到的新陣列, $x$ 為正整數。
對於所有的整數 $x$ 、非負整數 $i$ ,定義 $A(x)_0=0$ 、 $A(x)_{i+1}=A(x)_{i}+A(x-1)_{i+1}$ 。
舉例:
| $i$ | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
|:-------:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:--:|
|$A(1)_i$ | 0 | 1 | 3 | 6 | 10| 15| 21| 28| 36| 36| 36 |
|$A(0)_i$ | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 0 | 0 |
|$A(-1)_i$| 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -8| 0 |
## 觀察
$a_i$ 的初始值很好處理,為了方便觀察,不失一般性假設 $a_1~a_n$ 的初始值為 $0$ 。
假設 $n=10, k=3$ ,然後執行一次操作1,區間 $[l, r]$ 為 $[1, 5]$ 。
則結果為:
| $i$ | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
|:-------:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:--:|
|$A(0)_i$ | 0 | 1 | 8 | 27| 64|125| 0 | 0 | 0 | 0 | 0 |
|$A(-1)_i$| 0 | 1 | 7 | 19| 37| 61|-125| 0| 0 | 0 | 0 |
|$A(-2)_i$| 0 | 1 | 6 | 12| 18| 24|-186|125| 0| 0 | 0 |
|$A(-3)_i$| 0 | 1 | 5 | 6 | 6 | 6 |-210|311|-125|0| 0 |
|$A(-4)_i$| 0 | 1 | 4 | 1 | 0 | 0 |-216|521|-436|125| 0|
事實上,當 $k=3$ 時,不論 $n$ 有多大,每次執行操作1最多只會改變 $A(-4)$ 陣列中的7項。
更進一步的說,對於任意的 $k$ 值,不論 $n$ 有多大,每次執行操作1最多只會改變 $A(-k-1)$ 陣列中的 $O(k)$ 項。
這個結論除了可以用來解決此題的離線版本:「所有操作2皆發生在操作1之後」,
同時也為我們找到了「如何處理更大的 $k$ 」這個問題的思考方向。
## 推導
我們先解決 $k=0$ 的情況:
$A(0)_1+A(0)_2+A(0)_3+\dots+A(0)_{x-1}+A(0)_x$
$=\displaystyle\sum_{i=1}^{1}{A(-1)_i} +\displaystyle\sum_{i=1}^{2}{A(-1)_i}+\displaystyle\sum_{i=1}^{3}{A(-1)_i}+\dots+\displaystyle\sum_{i=1}^{x-1}{A(-1)_i}+\displaystyle\sum_{i=1}^{x}{A(-1)_i}$
$=\displaystyle\sum_{i=1}^{x}{\left(A(-1)_i\times((x+1)-i)\right)}\cdots\huge①$
$=(x+1)\displaystyle\sum_{i=1}^{x}{A(-1)_i}-\displaystyle\sum_{i=1}^{x}{(A(-1)_i\times i)}$
假設 $B_i=A(-1)_i\times i$ ,那我們只要用兩個BIT分別維護 $A(-1),B$ 兩陣列的值,就可以解決 $k=0$ 情況下的問題了。
根據上個章節的結論,只要把上式的 $A(-1)$ 想辦法代換成 $A(-2)$ ,那 $k=1$ 情況下的問題就解決了。
以下為代換過程:
$A(0)_1+A(0)_2+A(0)_3+\dots+A(0)_{x-1}+A(0)_x$
$=\displaystyle\sum_{i=1}^{x}{\left(A(-1)_i\times\left(\left(x+1\right)-i\right)\right)}\cdots\huge①$
$=\displaystyle\sum_{i=1}^{x}{\left(\left(\displaystyle\sum_{j=1}^{i}{A(-2)_j}\right)\times\left(\left(x+1\right)-i\right)\right)}$
$=\displaystyle x\left(\sum_{i=1}^{1}{A(-2)_i}\right)+\left(x-1\right)\left(\displaystyle\sum_{i=1}^{2}{A(-2)_i}\right)+\left(x-2\right)\left(\displaystyle\sum_{i=1}^{3}{A(-2)_i}\right)+\dots+2\left(\displaystyle\sum_{i=1}^{x-1}{A(-2)_i}\right)+1\left(\displaystyle\sum_{i=1}^{x}{A(-2)_i}\right)$
$=\displaystyle\sum_{i=1}^{x}{\left(A(-2)_i\times\sum_{j=1}^{x-i+1}{j}\right)}$
$=\displaystyle\sum_{i=1}^{x}{\left(A(-2)_i\times\frac{\left(x-i+1\right)\left(\left(x-i+1\right)+1\right)}{2}\right)}$
$=\displaystyle\frac{1}{2}\sum_{i=1}^{x}{\left(A(-2)_i\times\left(\left(x+1\right)-i\right)\left(\left(x+2\right)-i\right)\right)}\cdots\huge②$
$=\displaystyle\frac{1}{2}\left(\left(\sum_{i=1}^{x}{A(-2)_i\times\left(x+1\right)\left(x+2\right)}\right)-\left(\sum_{i=1}^{x}{A(-2)_i\times i\times\left(\left(x+1\right)+\left(x+2\right)\right)}\right)+\left(\sum_{i=1}^{x}{A(-2)_i\times {i^2}}\right)\right)$
$=\displaystyle\frac{1}{2}\left(\left({x^2}+3x+2\right)\left(\sum_{i=1}^{x}{A(-2)_i}\right)-\left(2x+3\right)\left(\sum_{i=1}^{x}{\left(A(-2)_i\times i\right)}\right)+\left(\sum_{i=1}^{x}{\left(A(-2)_i\times {i^2}\right)}\right)\right)$
假設 $B_i=A(-2)_i\times i, C_i=A(-2)_i\times {i^2}$ ,那我們只要改成用三個BIT分別維護 $A(-2), B, C$ 三陣列的值,就可以解決 $k=1$ 情況下的問題了。
接下來我們處理 $k=2$ 的情況,也就是把上式的 $A(-2)$ 代換成 $A(-3)$ :
$A(0)_1+A(0)_2+A(0)_3+\dots+A(0)_{x-1}+A(0)_x$
$=\displaystyle\frac{1}{2}\sum_{i=1}^{x}{\left(A(-2)_i\times\left(\left(x+1\right)-i\right)\left(\left(x+2\right)-i\right)\right)}\cdots\huge②$
$=\displaystyle\frac{1}{2}\sum_{i=1}^{x}{\left(\left(\displaystyle\sum_{j=1}^{i}{A(-3)_j}\right)\times\left(\left(x+1\right)-i\right)\left(\left(x+2\right)-i\right)\right)}$
$=\displaystyle\frac{1}{2}\left(A(-3)_1\times x\left( x+1 \right)+\left(A(-3)_1+A(-3)_2\right)\times \left( x-1 \right)\left(x\right)+\left(A(-3)_1+A(-3)_2+A(-3)_3\right)\times \left( x-2 \right)\left( x-1 \right)+\dots+\left(\displaystyle\sum_{i=1}^{n-1}{A(-3)_i}\right)\times \left(2 \times 3\right)+\left(\displaystyle\sum_{i=1}^{n}{A(-3)_i}\right)\times \left(1 \times 2\right)\right)$
$=\displaystyle\frac{1}{2}\sum_{i=1}^{x}{\left(A(-3)_i\times\sum_{j=1}^{x-i+1}{j \left( j+1 \right)}\right)}$
$=\displaystyle\frac{1}{2}\sum_{i=1}^{x}{\left(A(-3)_i\times\frac{\left( x-i+1 \right)\left( x-i+2 \right)\left( x-i+3 \right)}{3}\right)}$
$=\displaystyle\frac{1}{6}\sum_{i=1}^{x}{\left(A(-3)_i\times\left( \left( x+1 \right)-i \right)\left( \left( x+2 \right)-i \right)\left( \left( x+3 \right)-i \right)\right)}\cdots\huge③$
$=\displaystyle\frac{1}{6}\left(\left({x^3}+6{x^2}+11x+6\right)\left(\sum_{i=1}^{x}{A(-3)_i}\right)-\left(3x^2+12x+11\right)\left(\sum_{i=1}^{x}{\left(A(-3)_i\times i\right)}\right)+\left(3x+6\right)\left(\sum_{i=1}^{x}{\left(A(-3)_i\times {i^2}\right)}\right)-\left(\sum_{i=1}^{x}{\left(A(-3)_i\times {i^3}\right)}\right)\right)$
假設 $B_i=A(-3)_i\times i, C_i=A(-3)_i\times {i^2}, D_i=A(-3)_i\times {i^3}$ ,則我們能用四個BIT分別維護 $A(-3), B, C, D$ 四陣列的值來解決 $k=2$ 情況下的問題。
相信看到這裡,有人應該已經知道代換成 $A(-4)$ 的式子是什麼了,不過這個部分我們會留到下一章節,在這裡我們還是先單獨證明 $A(-4)$ 的版本:
$A(0)_1+A(0)_2+A(0)_3+\dots+A(0)_{x-1}+A(0)_x$
$=\displaystyle\frac{1}{6}\sum_{i=1}^{x}{\left(A(-3)_i\times\left( \left( x+1 \right)-i \right)\left( \left( x+2 \right)-i \right)\left( \left( x+3 \right)-i \right)\right)}\cdots\huge③$
$=\displaystyle\frac{1}{6}\sum_{i=1}^{x}{\left(\left(\displaystyle\sum_{j=1}^{i}{A(-4)_j}\right)\times\left( \left( x+1 \right)-i \right)\left( \left( x+2 \right)-i \right)\left( \left( x+3 \right)-i \right)\right)}$
$=\displaystyle\frac{1}{6}\left(A(-4)_1\times x\left( x+1 \right)\left( x+2 \right)+\left(A(-4)_1+A(-4)_2\right)\times \left( x-1 \right)\left(x\right)\left( x+1 \right)+\left(A(-4)_1+A(-4)_2+A(-4)_3\right)\times \left( x-2 \right)\left( x-1 \right)\left( x \right)+\dots+\left(\displaystyle\sum_{i=1}^{n-1}{A(-4)_i}\right)\times \left(2 \times 3\times 4\right)+\left(\displaystyle\sum_{i=1}^{n}{A(-4)_i}\right)\times \left(1 \times 2\times 3\right)\right)$
$=\displaystyle\frac{1}{6}\sum_{i=1}^{x}{\left(A(-4)_i\times\sum_{j=1}^{x-i+1}{j \left( j+1 \right)\left( j+2 \right)}\right)}$
$=\displaystyle\frac{1}{6}\sum_{i=1}^{x}{\left(A(-4)_i\times\frac{\left( x-i+1 \right)\left( x-i+2 \right)\left( x-i+3 \right)\left( x-i+4 \right)}{4}\right)}$
$=\displaystyle\frac{1}{24}\sum_{i=1}^{x}{\left(A(-4)_i\times\left( \left( x+1 \right)-i \right)\left( \left( x+2 \right)-i \right)\left( \left( x+3 \right)-i \right)\left( \left( x+4 \right)-i \right)\right)}\cdots\huge④$
$=\displaystyle\frac{1}{24}\left(\left({x^4}+10{x^3}+35{x^2}+50x+24\right)\left(\sum_{i=1}^{x}{A(-4)_i}\right)-\left(4{x^3}+30{x^2}+70{x}+50\right)\left(\sum_{i=1}^{x}{\left(A(-4)_i\times i\right)}\right)+\left(6{x^2}+30x+35\right)\left(\sum_{i=1}^{x}{\left(A(-4)_i\times {i^2}\right)}\right)-\left(4x+10\right)\left(\sum_{i=1}^{x}{\left(A(-4)_i\times {i^3}\right)}\right)+\left(\sum_{i=1}^{x}{\left(A(-4)_i\times {i^4}\right)}\right)\right)$
因此我們知道,總共用五棵BIT可以完成這題的所有限制: $0\leq k\leq 3$ 。
## 一般式
我想在這個章節之前,有人已經能猜到一般式是什麼了。
這邊公布答案:
$A(0)_1+A(0)_2+A(0)_3+\dots+A(0)_{x-1}+A(0)_x$
$=\displaystyle\frac{1}{k!}\sum_{i=1}^{x}{\left(A(-k)_i\prod_{j=1}^{k}{\left(x+j-i\right)}\right)}$
這個式子可以用數學歸納法來證明,具體來說要利用這個式子:
$\displaystyle\sum_{i=1}^{n}{\left(\prod_{j=0}^{m}{\left(i+j\right)}\right)}=\frac{1}{m+2}\prod_{j=0}^{m+1}{\left(n+j\right)}$
詳細過程請讀者自行證明,這裡不多做解釋。
## 操作的等價
我們知道,當 $k\leq 3$ 的時候,每次執行操作1都只會改變 $A(-4)$ 中的 $O(k)$ 項,但具體來說,這幾項到底會改變多少呢?
| $i$ | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
|:-------:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:--:|
|$A(0)_i$ | 0 | 1 |$8$| 27| 64|125| 0 | 0 | 0 | 0 | 0 |
|$A(-1)_i$| 0 | 1 | 7 | 19| 37| 61|-125| 0| 0 | 0 | 0 |
|$A(-2)_i$| 0 | 1 | 6 | 12| 18| 24|-186|125| 0| 0 | 0 |
|$A(-3)_i$| 0 | 1 | 5 | 6 | 6 | 6 |-210|311|-125|0| 0 |
|$A(-4)_i$| 0 | 1 | 4 | 1 | 0 | 0 |-216|521|-436|125| 0|
如果上面這個例子的操作區間 $[l, r]$ 不是 $[1, 5]$ ,那麼 $1, 4, 1, -216, 521, -436, 125$ 這七個數字會變成什麼呢?
經過觀察(建議讀者多試幾組不同的位置與區間大小)之後可以發現,這七個數字中 $1,4,1$ 是固定的,但 $-216, 521, -436, 125$ 這四個數字的值則是跟區間大小 $(r-l+1)$ 有關。
至於有什麼關聯呢?我們可以利用代數方法來計算。
令區間大小 $m=r-l+1$ ,
假設 $n=1000,k=3$ ,操作區間$[l, r]=[1, m]$ ,且$4\leq m\leq n-4$ :
| $i$ |$0$|$1$|$2$| $3$| $4$|$\dots$|$m-1$| $m$ |$m+1$|$m+2$|$m+3$|$m+4$|$m+5$|
|:-------:|:-:|:-:|:-:|:--:|:--:|:-----:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|$A(0)_i$ |$0$|$1$|$8$|$27$|$64$|$\dots$|$(m-1)^3$|$m^3$|$0$|$0$|$0$|$0$|$0$|
|$A(-1)_i$|$0$|$1$|$7$|$19$|$37$|$\dots$|$3m^2-9m+7$|$3m^2-3m+1$|$-m^3$|$0$|$0$|$0$|$0$|
|$A(-2)_i$|$0$|$1$|$6$|$12$|$18$|$\dots$|$6m-12$|$6m-6$|$-m^3-3m^2+3m-1$|$m^3$|$0$|$0$|$0$|
|$A(-3)_i$|$0$|$1$|$5$| $6$| $6$|$\dots$|$6$|$6$|$-m^3-3m^2-3m+5$|$2m^3+3m^2-3m+1$|$-m^3$|$0$|$0$|
|$A(-4)_i$|$0$|$1$|$4$| $1$| $0$|$\dots$|$0$|$0$|$-m^3-3m^2-3m-1$|$3m^3+6m^2-4$|$-3m^3-3m^2+3m-1$|$m^3$|$0$|
由此可以得知:
$-216, 521, -436, 125$
分別是:
$(-m^3-3m^2-3m-1),(3m^3+6m^2-4),(-3m^3-3m^2+3m-1),(m^3)$
代入 $m=5$ 的結果。
至於 $k=0, 1, 2$ 的操作對 $A(-4)$ 的變化,就交給讀者自行證明了,在下個章節的code也能找到答案。
## 實作方法
<!-- 說明待補 -->
:::spoiler code(C++)
```cpp=
#include <bits/stdc++.h>
#define loop(i,a,b) for(int i=a;i<b;i++)
using namespace std;
typedef long long ll;
const int mod = (int)(1e6) + 3;
const int inv_24 = 208334;
const int mxn = (int)(1e5) + 10;
int pref[mxn];
ll i0_BIT[mxn], i1_BIT[mxn], i2_BIT[mxn], i3_BIT[mxn], i4_BIT[mxn];
inline ll neg_mod(ll x){ return ((x % mod) + mod) % mod; }
inline int lowbit(int x){ return (x) & (-x); }
inline void upd(int ind, ll val){
for(int i = ind; i < mxn; i += lowbit(i))
(i0_BIT[i] += val) %= mod;
val = val * ind % mod;
for(int i = ind; i < mxn; i += lowbit(i))
(i1_BIT[i] += val) %= mod;
val = val * ind % mod;
for(int i = ind; i < mxn; i += lowbit(i))
(i2_BIT[i] += val) %= mod;
val = val * ind % mod;
for(int i = ind; i < mxn; i += lowbit(i))
(i3_BIT[i] += val) %= mod;
val = val * ind % mod;
for(int i = ind; i < mxn; i += lowbit(i))
(i4_BIT[i] += val) %= mod;
}
inline ll qry(ll ind){
int ret0 = 0, ret1 = 0, ret2 = 0, ret3 = 0, ret4 = 0;
for(int i = ind; i > 0; i -= lowbit(i)){
ret0 = (ret0 + i0_BIT[i] >= mod) ? (ret0 + i0_BIT[i] - mod) : (ret0 + i0_BIT[i]);
ret1 = (ret1 + i1_BIT[i] >= mod) ? (ret1 + i1_BIT[i] - mod) : (ret1 + i1_BIT[i]);
ret2 = (ret2 + i2_BIT[i] >= mod) ? (ret2 + i2_BIT[i] - mod) : (ret2 + i2_BIT[i]);
ret3 = (ret3 + i3_BIT[i] >= mod) ? (ret3 + i3_BIT[i] - mod) : (ret3 + i3_BIT[i]);
ret4 = (ret4 + i4_BIT[i] >= mod) ? (ret4 + i4_BIT[i] - mod) : (ret4 + i4_BIT[i]);
}
ll ind2 = ind * ind % mod;
ll ind3 = ind2 * ind % mod;
ll mul0 = (ind + 1) * (ind + 2) % mod * (ind + 3) * (ind + 4) % mod;
ll mul1 = mod - ((4 * ind3 + 30 * ind2 + 70 * ind + 50) % mod);
ll mul2 = (6 * ind2 + 30 * ind + 35) % mod;
ll mul3 = mod - ((4 * ind + 10) % mod);
static int mul4 = 1;
return (ret0 * mul0 + ret1 * mul1 + ret2 * mul2 + ret3 * mul3 + ret4 * mul4) % mod;
}
int main(){
ios::sync_with_stdio(false); cin.tie(0);
int n, k, q;
cin >> n >> k >> q;
loop(i,1,n+1){
cin >> pref[i];
(pref[i] += pref[i-1]) %= mod;
}
int cmd, l, r;
ll len, len2, len3;
loop(queries,0,q){
cin >> cmd >> l >> r;
len = r - l + 1;
if(cmd == 1){ // change value
if(k <= 1){
if(k == 0){
upd(l, 1);
upd(l + 1, mod - 3);
upd(l + 2, 3);
upd(l + 3, mod - 1);
upd(r + 1, mod - 1);
upd(r + 2, 3);
upd(r + 3, mod - 3);
upd(r + 4, 1);
}
else{
upd(l, 1);
upd(l + 1, mod - 2);
upd(l + 2, 1);
upd(r + 1, mod - len - 1);
upd(r + 2, len * 3 + 2);
upd(r + 3, mod - len * 3 - 1);
upd(r + 4, len);
}
}
else{
len2 = len * len % mod ;
if(k == 2){
upd(l, 1);
upd(l + 2, mod - 1);
upd(r + 1, mod - (len2 + (len << 1) + 1) % mod);
upd(r + 2, (3 * len2 + 4 * len) % mod);
upd(r + 3, (3 * (mod - len2) + 2 * (mod - len) + 1) % mod);
upd(r + 4, len2);
}
else{
len3 = len2 * len % mod;
upd(l, 1);
upd(l + 1, 4);
upd(l + 2, 1);
upd(r + 1, ((mod - len3) + 3 * (mod - len2) + 3 * (mod - len) + (mod - 1)) % mod);
upd(r + 2, (3 * len3 + 6 * len2 + (mod - 4)) % mod);
upd(r + 3, (3 * (mod - len3) + 3 * (mod - len2) + 3 * len + (mod - 1)) % mod);
upd(r + 4, len3);
}
}
}
else{ // ask value
int ans = ((qry(r) + mod - qry(l-1)) * inv_24 + (pref[r] + mod - pref[l-1])) % mod;
cout << ans << '\n';
}
}
}
```
:::
## 更好的複雜度
從上面的code可以發現,用 BIT 單次修改的複雜度為 $O(k^2\log n)$ ,如果用線段樹來做這題,複雜度只有 $O(\log n)$ ,而且實作更簡單,只需要知道求和公式就可以實作懶標了,至於常數的部分,BIT是否比線段樹好,我就沒有試過了。