高階資料結構(1) 線段樹與樹狀陣列

2021-08-15 09:48:07 字數 2481 閱讀 8629

鑑於去年西安賽區被吐槽為線段樹專題賽區,就先更一發線段樹2333333

線段樹(segment tree)本質上來講是一棵二叉搜尋樹。它與區間樹類似,它的每乙個結點都是一段區間。

線段樹的功能是快速查詢某個結點在若干線段中出現的次數,時間複雜度為o(logn),單純空間複雜度為o(2n)。

實際應用中,為了避免越界一般來說開4n的陣列。

樹狀陣列(binary indexed tree(b.i.t), fenwick tree)是乙個查詢和修改複雜度都為log(n)的資料結構。

主要用於查詢任意兩位之間的所有元素之和,但是每次只能修改乙個元素的值。

經過簡單修改可以在log(n)的複雜度下進行範圍修改,但是這時只能查詢其中乙個

元素的值(如果加入多個輔助陣列則可以實現區間修改與區間查詢)。

線段樹和樹狀陣列很類似,但樹狀陣列能解決的問題一般線段樹也能解決,而線段樹能解決的樹狀陣列就不一定了。

線段樹至少包含以下幾個操作:

1、insert(x):插入元素

2、delete(x):刪除元素

3、search(x):查詢元素

但是只有這幾個功能的話依舊沒有什麼用處。最簡單的應用就是記錄線段是否被覆蓋,隨時查詢當前被覆蓋線段的總長度。

那麼此時可以在結點結構中加入乙個變數int count;代表當前結點代表的子樹中被覆蓋的線段長度和。

這樣就要在插入(刪除)當中維護這個count值,於是當前的覆蓋總值就是根結點

的count值了。

實際上,通過在結點上記錄不同的資料,線段樹還可以完成很多不同的任務。

例如,如果每次插入操作是在一條線段上每個位置均加k,而查詢操作是計算一條線段上的總和,那麼在結點上需要記錄的值為sum。

線段樹的使用有許多技巧,例如離散化、lazy標記、掃瞄線、動態開點、合併、可持久化等等。

本日例題:

poj - 2528 

題意:n張海報等高依次貼在牆上,給出每張海報的覆蓋範圍。後貼的會把先貼的覆蓋掉,問最後能看到幾張海報。

分析:本題很明顯是一道線段樹+離散化的題。線段樹更新區間+染色。需要注意的是,給的長度可能非常大,有1e9.

如果裸開線段樹的話很容易就會tle或者mle了。但是最多只有2e4個點,所以我們可以對區間離散化預處理。

tip;什麼是離散化?

離散化就是類似於將大區間對映到小區間的一種手段。例如:[1,5],[2,10],[3,10]就可以離散化為[1,3],[2,5],[3,5]。

但是有個問題,當兩個相鄰區間的間隔大於1的時候,離散化可能會出現問題。

例如:[1,10],[1,4],[5,10]

以及:[1,10],[1,4],[6,10]

離散化之後均為[1,4],[1,2],[3,4],可以看到對於第二個例子來說是不正確的,所以遇到這種情況我們需要手動插入乙個結點。

此外本題還可以使用lazy標記,即等到詢問某個結點的時候再將之前的修改加入進去。

**如下:

#include#include#include#includeusing namespace std;

#define lson rt<<1,l,m

#define rson rt<<1|1,m+1,r

const int maxn=11111;

int col[maxn<<4];

int li[maxn<<2],ri[maxn<<2];

bool hash[maxn<<2];

int ans=0;

int x[maxn<<2];

int y[maxn<<2];

void pushdown(int rt)

}void update(int ql,int qr,int ch,int rt,int l,int r)

pushdown(rt);

int m=(l+r)>>1;

if(ql<=m)

update(ql,qr,ch,lson);

if(qr>m)

update(ql,qr,ch,rson);

}void query(int ql,int qr,int rt,int l,int r)

col[rt]=-1;

return ;

}if(l==r) return;

// pushdown(rt);

int m=(l+r)>>1;

if(ql<=m)

query(ql,qr,lson);

if(qr>=m)

query(ql,qr,rson);

}int bin(int ans,int x,int l,int r)

return l;

}int main()

sort(x+1,x+cnt);

int mm=cnt;

for(int i=2;i1)

x[mm++]=x[i-1]++;

}sort(x+1,x+mm);

int tt=2;

y[1]=x[1];

for(int i=2;i

資料結構習題 線段樹 樹狀陣列

說明 這是去年寫了一半的東西,一直存在草稿箱裡,今天整理東西的時候才發現,還是把它發表出來吧。以下所有題目來自lrj的 訓練指南 la 2191 單點修改,區間和 fenwick直接搞 uva 12299 給出n個數,支援迴圈移動某些數 30個 然後問區間最小值 因為移動小於30個數,所以直接單點修...

「高階」資料結構 樹狀陣列!

最簡單的樹狀陣列就是這樣的 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...

刷題 資料結構 樹狀陣列 線段樹

1 數星星 複製自他人部落格 由於題目中給的資料是按y軸排序,我們只需構建x軸的樹狀陣列,也就是說我們只需統計星星i之前一共有多少個x座標小於或等於xi的星星,這個數值也就是星星i的等級 又因為樹狀陣列無法處理下標為0的元素 會死迴圈 所以要把每個x座標 1 include include incl...