Java數(shù)據(jù)結(jié)構(gòu)之線段樹中的懶操作詳解
一、問題提出
對(duì)于線段樹,若要求對(duì)區(qū)間中的所有點(diǎn)都進(jìn)行更新,可以引入懶操作。
懶操作包括區(qū)間更新和區(qū)間查詢操作。
二、區(qū)間更新
對(duì) [l,r] 區(qū)間進(jìn)行更新,例如將 [l,r] 區(qū)間所有元素都更新為 v,步驟如下。
1.若當(dāng)前節(jié)點(diǎn)區(qū)間被查詢區(qū)間[l,r]覆蓋,則僅對(duì)該節(jié)點(diǎn)進(jìn)行更新并做懶標(biāo)記,表示該節(jié)點(diǎn)已被更新,對(duì)該節(jié)點(diǎn)的子節(jié)點(diǎn)暫不更新。
2.判斷是在左子樹中查詢還是在右子樹中查詢。在查詢過程中,若當(dāng)前節(jié)點(diǎn)帶有懶標(biāo)記,則將懶標(biāo)記傳給子節(jié)點(diǎn)(將當(dāng)前節(jié)點(diǎn)的懶標(biāo)記清除,將子節(jié)點(diǎn)更新并做懶標(biāo)記),繼續(xù)查找。
3.在返回時(shí)更新最值。
三、區(qū)間查詢
帶有懶標(biāo)記的區(qū)間查詢和普通的區(qū)間查詢有所不同,在查詢過程中若遇到節(jié)點(diǎn)有懶標(biāo)記,則下傳懶標(biāo)記,繼續(xù)查詢。
四、實(shí)戰(zhàn)
1.問題描述
2.輸入
10
5 3 7 2 12 1 6 4 8 15
3 7 25
1 10
3.代碼
package com.platform.modules.alg.alglib.p85; public class P85 { public String output = ""; private final int maxn = 100005; private final int inf = 0x3f3f3f3f; private int n; private int a[] = new int[maxn]; private node tree[] = new node[maxn * 4]; // 樹結(jié)點(diǎn)存儲(chǔ)數(shù)組 public P85() { for (int i = 0; i < tree.length; i++) { tree[i] = new node(); } } void lazy(int k, int v) { tree[k].mx = v; // 更新最值 tree[k].lz = v; // 做懶標(biāo)記 } // 向下傳遞懶標(biāo)記 void pushdown(int k) { lazy(2 * k, tree[k].lz); // 傳遞給左孩子 lazy(2 * k + 1, tree[k].lz); // 傳遞給右孩子 tree[k].lz = -1; // 清除自己的懶標(biāo)記 } // 創(chuàng)建線段樹,k表示存儲(chǔ)下標(biāo),區(qū)間[l,r] void build(int k, int l, int r) { tree[k].l = l; tree[k].r = r; tree[k].lz = -1; // 初始化懶操作 if (l == r) { tree[k].mx = a[l]; return; } int mid, lc, rc; mid = (l + r) / 2; // 劃分點(diǎn) lc = k * 2; // 左孩子存儲(chǔ)下標(biāo) rc = k * 2 + 1; // 右孩子存儲(chǔ)下標(biāo) build(lc, l, mid); build(rc, mid + 1, r); tree[k].mx = Math.max(tree[lc].mx, tree[rc].mx); // 結(jié)點(diǎn)的最大值等于左右孩子最值的最大值 } // 將區(qū)間 [l,r] 修改更新為 v void update(int k, int l, int r, int v) { // 找到該區(qū)間 if (tree[k].l >= l && tree[k].r <= r) { lazy(k, v); // 更新并做懶標(biāo)記 return; } if (tree[k].lz != -1) pushdown(k); // 懶標(biāo)記下移 int mid, lc, rc; mid = (tree[k].l + tree[k].r) / 2; // 劃分點(diǎn) lc = k * 2; // 左孩子存儲(chǔ)下標(biāo) rc = k * 2 + 1; // 右孩子存儲(chǔ)下標(biāo) if (l <= mid) update(lc, l, r, v); // 到左子樹更新 if (r > mid) update(rc, l, r, v);// 到右子樹更新 tree[k].mx = Math.max(tree[lc].mx, tree[rc].mx); // 返回時(shí)修改更新最值 } // 求區(qū)間 [l,r] 的最值 int query(int k, int l, int r) { int Max = -inf; if (tree[k].l >= l && tree[k].r <= r) // 找到該區(qū)間 return tree[k].mx; if (tree[k].lz != -1) pushdown(k); // 懶標(biāo)記下移 int mid, lc, rc; mid = (tree[k].l + tree[k].r) / 2; // 劃分點(diǎn) lc = k * 2; // 左孩子存儲(chǔ)下標(biāo) rc = k * 2 + 1; // 右孩子存儲(chǔ)下標(biāo) if (l <= mid) Max = Math.max(Max, query(lc, l, r)); // 到左子樹查詢 if (r > mid) Max = Math.max(Max, query(rc, l, r)); // 到右子樹查詢 return Max; } public String cal(String input) { int l, r; int i, v; String[] line = input.split("\n"); n = Integer.parseInt(line[0]); // 第 1 行:10 String[] nums = line[1].split(" "); // 第 2 行:5 3 7 2 12 1 6 4 8 15 for (i = 1; i <= n; i++) a[i] = Integer.parseInt(nums[i - 1]); build(1, 1, n); // 創(chuàng)建線段樹 // 輸入查詢最值的區(qū)間 [l,r] 1 10 String[] range = line[2].split(" "); l = Integer.parseInt(range[0]); r = Integer.parseInt(range[1]); // 求區(qū)間[l..r]的最值 output += query(1, l, r) + "\n"; // 輸入更新的區(qū)間值 l r v 第 3 行: 3 7 25 String[] change = line[3].split(" "); l = Integer.parseInt(change[0]); r = Integer.parseInt(change[1]); v = Integer.parseInt(change[2]); // 將區(qū)間 [l,r] 修改更新為 v update(1, l, r, v); // 求區(qū)間[l..r]的最值 第 4 行:1 10 range = line[4].split(" "); l = Integer.parseInt(range[0]); r = Integer.parseInt(range[1]); // 求區(qū)間 [l..r] 的最值 output += query(1, l, r) + "\n"; return output; } } // 結(jié)點(diǎn) class node { int l; // l 表示區(qū)間左右端點(diǎn) int r; // r 表示區(qū)間左右端點(diǎn) int mx; // mx表示區(qū)間[l,r]的最值 int lz; // lz 懶標(biāo)記 }
4.測試
以上就是Java數(shù)據(jù)結(jié)構(gòu)之線段樹中的懶操作詳解的詳細(xì)內(nèi)容,更多關(guān)于Java線段樹 懶操作的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
spring-data-redis自定義實(shí)現(xiàn)看門狗機(jī)制
redission看門狗機(jī)制是解決分布式鎖的續(xù)約問題,本文主要介紹了spring-data-redis自定義實(shí)現(xiàn)看門狗機(jī)制,具有一定的參考價(jià)值,感興趣的可以了解一下2024-03-03Java中Date時(shí)區(qū)的轉(zhuǎn)換代碼示例
這篇文章主要給大家介紹了關(guān)于Java中Date時(shí)區(qū)轉(zhuǎn)換的相關(guān)資料,當(dāng)在不同的時(shí)區(qū)使用相同程序,時(shí)間的值只會(huì)為當(dāng)?shù)貢r(shí)間,這樣就會(huì)造成時(shí)間混亂,需要的朋友可以參考下2023-07-07Java中的UrlDecoder 和 UrlEncoder_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
HTML 格式編碼的實(shí)用工具類。該類包含了將 String 轉(zhuǎn)換為 application/x-www-form-urlencoded MIME 格式的靜態(tài)方法。下文通過實(shí)例代碼給大家介紹Java中的UrlDecoder 和 UrlEncoder知識(shí),感興趣的的朋友一起看看吧2017-07-07Java數(shù)組中的元素刪除并實(shí)現(xiàn)向前移的代碼
這篇文章主要介紹了Java數(shù)組中的元素刪除并實(shí)現(xiàn)向前移的代碼的相關(guān)資料,需要的朋友可以參考下2016-05-05關(guān)于@RequestParam注解的使用(簡單易懂)
這篇文章主要介紹了關(guān)于@RequestParam注解的使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01Spring Security無法調(diào)用接口錯(cuò)誤的問題解決
記錄一下之前在寫程序的時(shí)候遇到的問題,Spring Security無法調(diào)用接口錯(cuò)誤的問題,本文就來介紹一下解決方法,感興趣的可以了解一下2023-08-08