動態範圍最小值問題。給出乙個有$n$個元素的陣列$a_1, a_2, ..., a_n$,你的任務是設計乙個資料結構,支援以下兩種操作:
如果還是使用$sparse-table$演算法,每次$update$操作都需要重新計算$d$陣列,時間無法承受。為了解決這個問題,這裡介紹一種靈活的資料結構:線段樹(segment tree).
在查詢時,我們從根節點開始自頂向下找到待查詢線段的左邊界和右邊界,則「夾在中間」的所有葉子結點不重複不遺漏地覆蓋了整個待查詢線段。從圖中不發現,樹的左右各有一條「主線」,雖然各自分叉,但每層最多只有兩個結點向下延伸,因此「查詢邊界」結點個數不超過$2h$個,其中$h$是線段樹的最大層編號。這實際上是把待查詢線段分成了不超過$2h$個不相交線段的並。在後文中,凡是遇到這樣的區間分解,就把分解得到的各個區間叫做邊界區間,因為它們對應於分解過程的遞迴邊界。
如何更新線段樹呢?顯然需要更新線段$[i, \ i]$對應的結點,然後還需要更新它的所有祖先結點。不發現,其他的值並沒有改變。
以下是**。這裡的$o$是當前結點編號,$l$和$r$是當前結點的左右端點。查詢時,全域性變數$ql$和$qr$分別代表查詢區間的左右端點;修改時,全域性變數$p$和$v$分別代表修改點位置和修改後的值。
1const
int inf = 0x3f3f3f3f;2
const
int maxn = 100000 + 10;3
int minv[maxn << 2];4
intn, a[maxn];56
void build(int o, int l, intr)7
16}1718
int ql, qr; //
查詢[ql, qr]中的最小值
19int query(int o,int l,int
r)20
2829
int p, v; //
修改a[p]=v
30void update(int o, int l, int
r)31
40 }
最後敘述一下建樹過程。一種方法是每讀入乙個元素$x$後執行修改操作$a[i]=x$,則時間複雜度為$o(nlogn)$。其實只需要事先設定好每個結點的值,自底向上遞推即可(也可以寫成遞迴)。每個結點僅計算了一次,因此為時間複雜度$o(n)$。
線段樹的一點總結
線段樹,顧名思義,是根據線段建成的樹。每乙個節點都可以是線段。對於單點查詢,區間查詢,單點更新,區間更新都是o logn 級別的,所以對於大多數區間操作比較大的題,都可以用線段樹解決。0.性質 對於每乙個非葉子節點下標為i的節點,它的左兒子的下標必定為i 1,右兒子的下標必定為i 1 1.1.定義 ...
Lost Cows 線段樹點修改
題目大意 有編號為1 n的n頭牛,已知排在第i頭牛前面且比第i頭牛編號小的牛的數量為ai,求第i頭牛的編號 input c組資料,每組陣列乙個n,接著n個數字表示排在第i位的牛的ai.output 按順序輸出每位牛的編號.思路 從最後一頭牛開始,ans i 剩餘編號中的第ai小的編號,include...
線段樹 點修改 hdoj 1754
problem description 很多學校流行一種比較的習慣。老師們很喜歡詢問,從某某到某某當中,分數最高的是多少。這讓很多學生很反感。不管你喜不喜歡,現在需要你做的是,就是按照老師的要求,寫乙個程式,模擬老師的詢問。當然,老師有時候需要更新某位同學的成績。input 本題目包含多組測試,請處...