# Iterative-SegmentTree [by OmeletWithouEgg](https://omeletwithoutegg.github.io/2019/12/07/Iterative-SegmentTree/) ###### tags: `Algorithm` --- ## 例題 RMQ 給出序列, 支援幾個操作 * 查詢區間最大值 query(l,r) * 區間加值 modify(l,r,x) ---- ![](https://i.imgur.com/lpLL3hb.png) --- ## construct ![](https://i.loli.net/2019/04/28/5cc4887f8a752.png ) ---- ```cpp const int N = 1<<18; int tr[N<<1], n; ``` * root := *1* * left node:= *i<<1* * right node:= *i<<1|1* * parent:= *i>>1* * brother:= *i^1* * leaf:= n~2n-1 * others:= 1~n-1 ---- ## build ```cpp void build(int v[]) { for(int i = 0; i < n; i++) tr[i+n] = v[i]; for(int i = n-1; i > 0; i--) tr[i] = max(tr[i<<1], tr[i<<1|1]); } ``` ---- ## modify 從底部開始 ```cpp void modify(int p, int x) { for(tr[p+=n] = x; p > 1; p>>=1) tr[p>>1] = max(tr[p],tr[p^1]); } ``` ---- ## query without recursive * 從底部開始 (l>>=1, r>>=1) * `query [l,r)` * l 是右子樹 * `res += tr[l++]` * r 是左子樹 * `res += tr[--r]` ---- ```cpp int query(int l, int r) { // [l,r) int res = -1e9; for(l+=n,r+=n; l<r; l>>=1,r>>=1) { if(l&1) res = max(res, tr[l++]); if(r&1) res = max(res, tr[--r]); } return res; } ``` --- ## Lazy tag lazy tag 顧名思義懶得做 那就把改變先記起來 等到有需要在做 ---- #### Modify: 0. 先把要更新的區域的 tag 往下推掉(push) * push(l+n), push(r-1+n) 2. 一直拆分更新區域, 直到完全覆蓋更新區域 3. 之後直接更新該節點的值, 並且在該點標上 lazy tag, 代表子節點還沒加上去的值 4. 往上把更新值後, 受影響的父節點更新掉(pull) ---- #### Query 0. 先把要詢問的區域的 tag 往下推掉 * push(l+n), push(r-1+n); 2. 直接查詢 ---- ### 實作 ---- ### upd (int i, int x) 改變值且更新 LazyTag ```cpp void upd(int p, int x) { tr[p] += x; if(p < n) tag[p] += x; } ``` ---- ### push (int i) 由上往下把 tag 都推下來 ```cpp void push(int p) { for(int h = __lg(n); h >= 0; h--) { int i = p>>h; // hth ancestor of p if(!tag[i>>1]) continue; upd(i, tag[i>>1]); upd(i^1, tag[i>>1]); tag[i>>1] = 0; } } ``` ---- ### pull (int i) 由下往上把更新過後的值 拿去更新父節點 ```cpp void pull(int p) { while(p > 1) { // do not forget the tag[p>>1] term tr[p>>1] = max(tr[p],tr[p^1])+tag[p>>1]; p >>= 1; } } ``` ---- ### query (int l, int r) ```cpp int query(int l,int r) { push(l+n), push(r-1+n); int res = -1e9; for(l+=n,r+=n; l<r; l>>=1,r>>=1) { if(l&1) res = max(res, tr[l++]); if(r&1) res = max(res, tr[--r]); } return res; } ``` ---- ### modify (int l, inr r, int x) ```cpp void modify(int l,int r, int d) { int tl = l, tr = r; push(l+n), push(r-1+n); for(l+=n,r+=n; l<r; l>>=1,r>>=1) { if(l&1) upd(l++, d); if(r&1) upd(--r, d); } // uses tl,tr here for l,r changed pull(tl+n), pull(tr-1+n); } ```
{"metaMigratedAt":"2023-06-15T02:51:47.865Z","metaMigratedFrom":"Content","title":"Iterative-SegmentTree","breaks":true,"contributors":"[{\"id\":\"aeea178b-8721-4c2d-ab07-8fc15a809855\",\"add\":4945,\"del\":2254}]"}
    374 views