線段樹和樹狀陣列

2022-01-26 04:09:13 字數 2420 閱讀 5439

引入1:有n個數(n<=50000)個數,m(m<=50000)次詢問。每次詢問區間l到r的數的和。要求輸出每一次詢問的結果......

分析:1.用字首和問題進行求解:再開乙個陣列(暫且記為b[n],設n個數所組成的陣列為a[n]),b[i]用來記錄從a[1]到a[i]的所有數字的和(即 b[1]=a[1],b[2]=b[1]+a[2],...,b[i]=b[i-1]+a[i])。這樣對於m次詢問,只需要對陣列b進行相應的操作就可以了。

eg:求陣列a中區間[l,r]的所有數字的和sum,即sum=a[l]+a[l+1]+...+a[r-1]+a[r]。由於我們之前已經對陣列a求了字首和,並得到字首和陣列b[n]。因此對b[n]進行操作就可以了,即sum=b[r]-b[l-1]。

2.用線段樹進行求解:這裡先告訴大家可以用線段樹來進行求解,具體如何求解我們可以等對線段樹進行一定的講解後再來進行求解。

引入2:rmq(range minimum/maximum query)問題

有n(n<=50000)個數,m(m<=50000)次詢問,要求每次輸出區間[l,r]的數的最大值。

分析:1.用st表進行求解:一種利用dp思想求解區間最值的倍增演算法。

定義:f(i,j)表示[i,i+\(2^j\)−1]這段長度為2^j的區間中的最大值。

預處理:f(i,0)=a[i]。即[i,i]區間的最大值就是a[i]。

狀態轉移:將[i,j]平均分成兩段,一段為[i,i+2(j−1)−1],另一段為[i+2(j−1),i+2j−1]。兩段的長度均為2(j−1)。f(i,j)的最大值即這兩段的最大值中的最大值。得到f(i,j)=max。

查詢:若需要查詢的區間為[i,j],則需要找到兩個覆蓋這個閉區間的最小冪區間。

這兩個區間可以重複,因為兩個區間是否相交對區間最值沒有影響。(如下圖)

當然求區間和就肯定不行了。這也就是rmq的限制性。

因為區間的長度為j−i+1,所以可以取k=\(\log_2 (j-i+1)\)。

則所求即為max。

參考**如下:

#include//這段**以詢問最大值為例

#include#includeusing namespace std;

int a[50005];

int f[50005][16];

int main()

int mid=(l+r)/2;

buildtree(p*2,l,mid);//建立左子樹

buildtree(p*2+1,mid+1,r);//建立右子樹

tree[p]=tree[p*2]+tree[p*2+1];

}

-更新操作和查詢操作類似,時間複雜度都為o(logn)。當執行更新操作時,要遍歷到葉子節點,再層層遞迴更新,而查詢操作只需要查詢到包括的區間為止。

更新操作如下:

void change(int p,int l, int r,int x, int num)//給下標為x的位置加上num

int mid=(l+r)/2;

if(x<=mid)

else

tree[p]=tree[p*2]+tree[p*2+1];

}

查詢操作如下:

int query(int p,int l,int r, int x, int y)

完整**如下:

#includeusing namespace std;

int arr[10005],tree[10005];

void buildtree(int p, int l,int r)//p:陣列下標;l:區間左端點;r:區間右端點

int mid=(l+r)/2;

buildtree(p*2,l,mid);//建立左子樹

buildtree(p*2+1,mid+1,r);//建立右子樹

tree[p]=tree[p*2]+tree[p*2+1];

}void change(int p,int l, int r,int x, int num)//給下標為x的位置加上num

int mid=(l+r)/2;

if(x<=mid)

else

tree[p]=tree[p*2]+tree[p*2+1];

}int query(int p,int l,int r, int x, int y)

int main()

while(k--)

{int x,y;

cin>>x>>y;

cout<線段樹和樹狀陣列的題單:

樹狀陣列和線段樹

主要解決兩個問題 其他問題可以轉化 更新某一點的值 求區間值 時間按複雜度 logn 原陣列a 1 a 2 a n 寫成樹狀陣列c c x x lowbit x x 左開右閉 筆記 主要 const int n int tr n int lowbit int x void add int x,int...

線段樹和樹狀陣列

線段樹 segment tree 和樹狀陣列是兩種常用的資料結構。他們用來維護乙個區間內的操作,可以在 logn 的複雜度上進行查詢和修改。線段樹可以維護對乙個區間的查詢和修改,可以對區間進行分塊查詢,而樹狀陣列是線段樹的閹割版,經常用來區間查詢,但修改只能進行單點修改,經過改造之後可以區間修改,區...

樹狀陣列和線段樹(未完)

線段樹是一種二叉搜尋樹,與區間樹相似,它將乙個區間劃分成一些單元區間,每個單元區間對應線段樹中的乙個葉結點。效能 於tsinghua online judge,侵刪 題目描述 魔術師將一疊撲克順次在桌上排成一行,全部正面朝上。之後的每一次揮一揮衣袖,都會翻轉一連串的撲克,改變它們的正反朝向。從古代傳...