鑑於去年西安賽區被吐槽為線段樹專題賽區,就先更一發線段樹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...