|
今天我們分享一下樹(shù)狀數(shù)組,前置知識(shí)-了解樹(shù)的結(jié)構(gòu),知道什么是左右兒子,各個(gè)節(jié)點(diǎn)的名稱,也就是有點(diǎn)基礎(chǔ)吧。今天以一個(gè)實(shí)際問(wèn)題引出樹(shù)狀數(shù)組吧,中查詢l-r的區(qū)間。(以B站大佬的課件為例子,可以關(guān)注下,在最后放上鏈接)
如果是暴力的話,顯然時(shí)間復(fù)雜度是接受不了的(o(n方)),為了解決這個(gè)問(wèn)題,我們就要用一些高級(jí)的數(shù)據(jù)結(jié)構(gòu)。就是我們今天介紹的樹(shù)狀數(shù)組。 首先看下樹(shù)狀數(shù)組是什么, 樹(shù)狀數(shù)組(Binary Indexed Tree(B.I.T), Fenwick Tree)是一個(gè)查詢和修改復(fù)雜度都為log(n)的數(shù)據(jù)結(jié)構(gòu)。主要用于查詢?nèi)我鈨晌恢g的所有元素之和,但是每次只能修改一個(gè)元素的值;經(jīng)過(guò)簡(jiǎn)單修改可以在log(n)的復(fù)雜度下進(jìn)行范圍修改,但是這時(shí)只能查詢其中一個(gè)元素的值(如果加入多個(gè)輔助數(shù)組則可以實(shí)現(xiàn)區(qū)間修改與區(qū)間查詢)。 這種數(shù)據(jù)結(jié)構(gòu)(算法)并沒(méi)有C 和Java的庫(kù)支持,需要自己手動(dòng)實(shí)現(xiàn)。在Competitive Programming的競(jìng)賽中被廣泛的使用。樹(shù)狀數(shù)組和線段樹(shù)很像,但能用樹(shù)狀數(shù)組解決的問(wèn)題,基本上都能用線段樹(shù)解決,而線段樹(shù)能解決的樹(shù)狀數(shù)組不一定能解決。相比較而言,樹(shù)狀數(shù)組效率要高很多。(百度上的) 然后在介紹前綴和,b[1] = a[1],b[2] = a[1] a[2],b[3] = a[1] a[2] a[3]........b[n] = a[1] a[2] a[3] ..... a[n].這就是前綴和的概念,其實(shí)樹(shù)狀數(shù)組就是在維護(hù)一個(gè)前綴和。 再介紹lowbit函數(shù),用于再左右兒子或者是父節(jié)點(diǎn),偽代碼為 return x & (-x),就是返回某個(gè)數(shù)二進(jìn)制從右往左的第一個(gè)一所代表的數(shù),x于lowbit函數(shù)的關(guān)系如下、![]() 一個(gè)左兒子的父節(jié)點(diǎn)表示為x lowbit(x),同理右兒子的父親表示為 x - lowbit(x),把圖畫(huà)出來(lái),是不是很像二叉搜索樹(shù), 最后,給個(gè)樹(shù)狀數(shù)組的模板題吧, 如題,已知一個(gè)數(shù)列,你需要進(jìn)行下面兩種操作: 1.將某區(qū)間每一個(gè)數(shù)加上x(chóng) 2.求出某區(qū)間每一個(gè)數(shù)的和 輸入輸出格式輸入格式: 第一行包含兩個(gè)整數(shù)N、M,分別表示該數(shù)列數(shù)字的個(gè)數(shù)和操作的總個(gè)數(shù)。 第二行包含N個(gè)用空格分隔的整數(shù),其中第i個(gè)數(shù)字表示數(shù)列第i項(xiàng)的初始值。 接下來(lái)M行每行包含3或4個(gè)整數(shù),表示一個(gè)操作,具體如下: 操作1: 格式:1 x y k 含義:將區(qū)間[x,y]內(nèi)每個(gè)數(shù)加上k 操作2: 格式:2 x y 含義:輸出區(qū)間[x,y]內(nèi)每個(gè)數(shù)的和 輸出格式: 輸出包含若干行整數(shù),即為所有操作2的結(jié)果。(洛谷的題,https://www./problemnew/show/P3372) 輸入樣例 5 5 輸出樣例 11 附上AC代碼 #include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1e7 5;
int n,m,a;
int d[N]; //存前綴和的數(shù)組
int lowbit(int x)
{
return x & (-x);
}
int query(int x) //查詢操作
{
int res = 0;
while(x) //x > 0,x從左邊找父親節(jié)點(diǎn)相加
{
res = d[x];
x -= lowbit(x);
}
return res;
}
void add(int x,int val)
{
while(x <= n)
{
d[x] = val;
x = lowbit(x); //從左到右構(gòu)建樹(shù)狀數(shù)組
}
}
int sum(int x)
{
int total = 0;
while(x != 0)
{
total = d[x];
x -= lowbit(x);
}
return total;
}
int main()
{
cin >> n >> m;
for(int i = 1;i <= n;i )
{
cin >> a;
add(i,a);
}
while(m--)
{
int f,x,y;
cin >> f >> x >> y;
if(f == 1)
{
add(x,y);
}
if(f == 2)
{
cout << sum(y) - sum(x - 1) << endl;
}
}
return 0;來(lái)源:http://www./content-1-141701.html
|
|
|
來(lái)自: 印度阿三17 > 《開(kāi)發(fā)》