樹狀陣列的整理

2022-07-31 23:48:12 字數 3634 閱讀 4147

* 如m = 11000, 則c[m] = c[10100] + c[10110] + c[10111] + a[11000];

則s[m] = c[11000] + c[10000];

1.區間求和

向上更新每乙個父節點,向下統計每乙個子節點之和;

2.查詢單點

向上更新區間(update(l,1) /*以左端點為起點++*/,update(r+1,-1)/*以右端點為起--*/),向下統計子節點之和;

反過來,向下更新向上統計也可以;

* 1.樹狀陣列的起點從1開始,到最大值結束,因此終點n不是個數而是最大值;

2.空間複雜度為n,即陣列大小為n;

**模版:

void update(int pos,int

val)

}int sum(int

end)

return

ret;

}

3.求逆序數對於乙個序列求每個數前面比它大或小的數的個數的總和,將數字離散化得到大小關係用樹狀陣列求和;

/*離散化:當資料只與它們之間的相對大小有關,而與具體是多少無關時,可以進行離散化。*/

**模版:

for(int i=0;i)

sort(arr,arr+n,cmp);

for(int i=0;i)

reflect[arr[i].pos] =i;

for(int i=0;i)

4.二維樹狀陣列:原理與一維相同,將陣列變為二維陣列;

**模版:

void update(int x,int y,int

val)

int sum(int x,int

y)

hdu1556

輸入n,有1-n的數,輸入n個區間,每次把區間內的數+1;

輸出每個數的值;

/* 就是更新區間,查詢單點 */

**:

const

int maxn = 1e5+7

;int

c[maxn],n;

void add(int end,int

val)

}int sum(int

x)

return

ret;

}int

main()

for(int i=1;i)

printf(

"%d

",sum(i));

printf(

"%d\n

",sum(n));}}

poj 2352

輸入n,輸入n個點的x和y,輸入按y1 == y2 ? x1 < x2 : y1 < y2的順序;

輸出對於每個點,在它左下方的點的個數;

/* 輸入按照y的從小到大的順序,那麼後輸入的數必然在前輸入的數的右邊或上面,因此可以將所有的點全都投影到x軸上,只需要統計在此之前輸入的點中在當前點左邊的點的個數

*/**:

const

int maxn = 32005

;int

c[maxn],level[maxn],n;

void add(int

pos)

}int sum(int

end)

return

ret;

}int

main()

for(int i=0;i)

printf(

"%d\n

",level[i]);

}

poj2155

對於乙個n*n的零矩陣,輸入n和操作次數t,對於每次操作,若輸入為c x1 y1 x2 y2,表示將該子矩陣範圍內的數反轉,若輸入為q x1,y1,表示輸出點(x1,y1)的值

/*乙個二維的樹狀陣列,每次將區間內的數+1,查詢單點時輸出數取mod2*/

**:

const

int maxn = 1007

;int

c[maxn][maxn],n;

void update(int x,int

y)int sum(int x,int

y)int

main()

else

}printf("\n

");}

}

poj2299

輸入n,輸入n個數;

求這個序列的逆序數;

/*資料範圍有1e9不可以直接儲存在陣列裡,但是只要得到序列的相對大小,所以離散化後用樹狀陣列求和*/

**:

const

int maxn = 5e5+7

;struct

nodearr[maxn];

intn,c[maxn],reflect[maxn];

bool

cmp(node a,node b)

void update(int

pos)

}ll sum(

intend)

return

ret;

}int

main()

sort(arr,arr+n,cmp);

for(int i=0;i)

reflect[arr[i].pos] =i;

for(int i=0;i)

cout

<< ans

poj3067

輸入n,m,k,左邊有1-n的點,右邊有1-m的點,有k條線段連線左右的點,每次輸入線段的左端點和右端點;

輸出每兩條線段的交點的總個數和;

/*排序之後用樹狀陣列計算每個點前出現的比當前點小的點的個數,用i-當前個數加到總和裡*/

**:

const

int maxn = 1e6+7

;struct

nodea[maxn];

int n,m,k,c[1007

];bool

cmp(node x,node y)

void update(int

pos)

}ll sum(

intend)

return

ret;

}int

main()

printf(

"test case %d: %lld\n

",t,ans);}}

poj1195

1 x y a 表示把(x,y)的值+a,2 l b r t表示輸出(l,b)(r,t)範圍內的數的和;

/*二維的樹狀陣列求和*/

**:

const

int maxn = 1100

;int

c[maxn][maxn],s;

void update(int x,int y,int

val)

ll sum(

int x,int

y)int

main()

else

if(n == 2

) }}

樹狀陣列2 更高深的樹狀陣列

一 區間修改區間求和 這個東西可就不是把 單點查詢區間修改 和 單點修改區間查詢 合起來那麼簡單了,仔細想想,拿之前的辦法都不咋地好做,那麼怎麼辦呢,我們還是要用到差分陣列,設原陣列為a,差分陣列為b,則b 1 a 1 b i a i a i 1 那麼區間修改我們就解決了,只需要log的時間即可,但...

樹狀陣列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 下...