樹狀陣列(碼住細看)

2021-08-21 23:58:07 字數 2209 閱讀 7129

最簡單的樹狀陣列就是這樣的:

void add(int p, int x)

int ask(int p)

int range_ask(int l, int r)

通過「差分」(就是記錄陣列中每個元素與前乙個元素的差),可以把這個問題轉化為問題1。

設原陣列為a[i], 設陣列d[i]=a[i]−a[i−1](a[0]=0),則 a[i]=∑ij=1d[j],可以通過求d[i]的字首和查詢。

當給區間[l,r]加上x的時候,a[l] 與前乙個元素 a[l−1] 的差增加了x,a[r+1] 與 a[r] 的差減少了x。根據d[i]陣列的定義,只需給a[l] 加上 x, 給a[r+1] 減去 x即可。

void add(int p, int x)

void range_add(int l, int r, int x)

int ask(int p)

這是最常用的部分,也是用線段樹寫著最麻煩的部分——但是現在我們有了樹狀陣列!

怎麼求呢?我們基於問題2的「差分」思路,考慮一下如何在問題2構建的樹狀陣列中求字首和:

位置p的字首和 =∑i=1pa[i]=∑i=1p∑j=1id[j]在等式最右側的式子∑pi=1∑ij=1d[j]中,d[1] 被用了p次,d[2]被用了p−1

次……那麼我們可以寫出:位置p的字首和 =∑i=1p∑j=1id[j]=∑i=1pd[i]∗(p−i+1)=(p+1)∗∑i=1pd[i]−∑i=1pd[i]∗i

那麼我們可以維護兩個陣列的字首和:乙個陣列是 sum1[i]=d[i],另乙個陣列是 sum2[i]=d[i]∗i。

位置p的字首和即: (p + 1) * sum1陣列中p的字首和 - sum2陣列中p的字首和。

區間[l, r]的和即:位置r的字首和 - 位置l的字首和。

對於sum1陣列的修改同問題2中對d陣列的修改。

對於sum2陣列的修改也類似,我們給 sum2[l] 加上 l * x,給 sum2[r + 1] 減去 (r + 1) * x。

void add(ll p, ll x)

void range_add(ll l, ll r, ll x)

ll ask(ll p)

ll range_ask(ll l, ll r)

用這個做區間修改區間求和的題,無論是時間上還是空間上都比帶lazy標記的線段樹要優。

**另乙個大佬

#include#include#include#includeusing namespace std;

int n,m;

int c[500005];

int lowbit(int x)

void add(int pos,int x)

}void input()

}int query(int pos)

return res;

}int main()

void add(int pos,int x)

}int query(int pos)

return res;

} int main()

int opt,k;

for(int i=1;i<=m;i++)

else if(opt==2)

}return 0;

}

此處簡略地說明一下原陣列a,差分陣列d 則有an=∑i=1ndi所以∑i=1nai=∑i=1n∑j=1idj=∑i=1n(n−i+1)×di=(n+1)×∑i=1ndi−∑i=1ndi×i

於是我們維護兩個樹狀陣列,c1儲存di,c2儲存di×i

#include#include#includeusing namespace std;

long long c[200005][2];

int n,q;

int lowbit(int x)

void add(int pos,int x,int f)

}long long query(int pos,int f)

return res;

}long long ask(int pos)

int main()

scanf("%d",&q);

for(int i=1;i<=q;i++)

else if(opt==2)

}return 0;

}

樹狀陣列1 樹狀陣列入門

仔細看一下,發現tree的每乙個節點的高度並不是隨意的,而是由它轉成二進位制之後末尾連續零的數量決定的,連續零的數量加1,就是高度,例如 3 11 零的數量為0,加1等於1,所以它的高度就是1 6 110 零的數量為1,加1等於2,所以它的高度就是2 8 1000 零的數量為3,加1等於4,所以它的...

樹狀陣列 瞎bb 樹狀陣列

樹狀陣列是乙個利用一維陣列和位運算組成的求解區間問題的高效資料結構,其構造如圖所示 首先,我們要用它解決單點修改 區間查詢的操作。根據這張圖我們建立乙個陣列bit,下標就是圖中顯示的十進位制數。bit i 就表示了圖中所示的一段區間的和,例如bit 6 sum 5,6 bit 4 sum 1,4 下...

Lambda 表示式(一) 碼住

lambda 表示式是一種可用於建立委託或表示式目錄樹型別的匿名函式。通過使用 lambda 表示式,可以寫入可作為引數傳遞或作為函式呼叫值返回的本地函式。lambda 表示式對於編寫 linq 查詢表示式特別有用。若要建立 lambda 表示式,需要在 lambda 運算子 左側指定輸入引數 如果...