題解 P3374 模板 樹狀陣列 1

2022-05-03 17:42:12 字數 1857 閱讀 5067

恩,這是ac的第一道樹狀陣列呢。

如今終於找到了折中方案:樹狀陣列!!!!

**量小,還支援修改!

樹狀陣列也就是二叉索引樹,又被稱為fenwick樹,然而我個人認為它不能被嚴謹地成為樹,因為充其量只是借用的樹形結構的思想,於實現上有著較大的區別。

樹狀陣列雖然運用範圍沒有線段樹那麼廣,但是它的效率要高很多,比如線段樹是$nlogn$,但樹狀陣列是$logn$。

還有一點需要注意的是:樹狀陣列可以區間查詢,但不能運用於任意區間查詢。這一點在後面會提到。

那麼這個樹狀陣列的基本思路就是

用節點ci儲存和,比如:

- c1=a1

- c2=a1+a2

- c3=a3

- c4=a1+a2+a3+a4

- c5=a5

- c6=a5+a6

- c7=a7

- c8=a1+...+a8

當然這樣子可能不是很容易看出內在的聯絡,因此不妨將其轉化為二進位制來觀察:

- c0001=a0001

- c0010=a0001+a0010

- c0011=a0011

- c0100=a0001+a0010+a0011+a0100

- c0101=a0101

- c0110=a0101+a0110

- c0111=a0111

- c1000=a0001+...+a1000

是不是發現了什麼?

沒有嗎?好吧。

事實上這裡的規律就是cn=a(n–2^k+1)+...+an,這裡的k指的是n二進位制末尾0的數量

獲取2^k的操作我們稱之為lowbit,其實現如下:

int lowbit(int

k)

有了lowbit操作之後,求和就很好寫了:

1

int query(intx)7

return

ans;

8 }

要注意一點,這裡求的ans是區間[1,x]的和,想要[y,x]的和只能$query(x)-query(y-1)$。

因此我們回到了之前那個問題:樹狀陣列不能解決所有區間查詢,它只能解決如上的有關聯的區間查詢。

emmmm.....還有update操作:

1

void update(int x,int

k)6 }

這個在明白了樹狀陣列的本質之後也很好理解,就不多做敘述了。

總的來說,樹狀陣列挺好用的,值得一學。但切記,無論如何都必須掌握線段樹,因為能用樹狀陣列解決的都能用線段樹,而反之不一定如此。

另附ac**見下:

1 #include2 #include3 #include4

using

namespace

std;56

const

int maxn=500500;7

8int

n,m;

9int tree[maxn<<2

];10

11int lowbit(int

k)14

15void update(int x,int

k)20}21

22int query(int

x)28

return

ans;29}

3031

intmain()

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

44 }

P3374 模板 樹狀陣列 1 題解

同步 原題鏈結 給定乙個長度為 n nn 的陣列,q qq 組操作 顯然,假設你現在什麼也不會。我們只考慮第 2 22 個操作,即先不考慮修改,如何處理區間和的詢問?顯然,對於初始的陣列 a ia i ai 只需要做乙個字首和 s ss 使得 s j i 1 ja is j sum j a i sj...

題解 P3374 模板 樹狀陣列 1

最簡單的zkw線段樹就十分適合這道題,為什麼用zkw線段樹,可以看一下以下精簡 我們只需要用到單點修改,區間查詢就好了。include define go i,j,n,k for int i j i n i k define fo i,j,n,k for int i j i n i k define...

P3374 模板 樹狀陣列 1

如題,已知乙個數列,你需要進行下面兩種操作 1.將某乙個數加上x 2.求出某區間每乙個數的和 輸入格式 第一行包含兩個整數n m,分別表示該數列數字的個數和操作的總個數。第二行包含n個用空格分隔的整數,其中第i個數字表示數列第i項的初始值。接下來m行每行包含3個整數,表示乙個操作,具體如下 操作1 ...