線段樹

線段樹用于維護區(qū)間信息(要求滿足結合律)。與樹狀數(shù)組相比塞关,它可以實現(xiàn)O({\bf log}\ n)區(qū)間修改,還同時支持加墩新、乘操作马澈,更具有通用性瓢省。

在最后給出動態(tài)開點的線段樹。

線段樹的建立

線段樹是一顆平衡二叉樹痊班,母結點代表整個區(qū)間的和勤婚,越往下區(qū)間越小。線段樹的每個結點對應一條線段涤伐,但并不保證所有的線段都是線段的結點馒胆。

每個結點p的左右節(jié)點編號分別為2p2p+1,如果節(jié)點p儲存區(qū)間[a,b]的和凝果,那么子節(jié)點分別存儲[a,mid][mid+1,r]祝迂,其中mid=\left \lfloor \frac{a+b}{2} \right \rfloor

左節(jié)點對應的區(qū)間長度與右節(jié)點數(shù)相同或者比之恰好多1器净。

區(qū)間修改

線段樹能夠實現(xiàn)高效的區(qū)間修改是由于其引入了一個懶標記/延遲標記型雳。懶標記的存在使區(qū)間修改不再繼續(xù)遞歸下去,而去打上一個懶標記山害,將來要用到他的子區(qū)間時纠俭,再向下傳遞。

懶標記如其名浪慌,只有要用到子區(qū)間時它的子區(qū)間才會在向下傳遞一層(你推他一下他走一步的感覺)柑晒。

在進行區(qū)間修改時,從最大的區(qū)間開始眷射,遞歸向下處理匙赞。遞歸過程中,記當前節(jié)點為node妖碉,當前區(qū)間為[cl,cr]涌庭,目標區(qū)間為[l,r],我們會遇到三種情況:

  1. 當前區(qū)間于目標區(qū)間無交集欧宜,此時遞歸結束坐榆。
  2. 當前區(qū)間在目標區(qū)間之中,此時更新當前區(qū)間冗茸,并打上懶標記(此前可能存在標記)席镀,遞歸結束匹中。
  3. 當前區(qū)間與目標區(qū)間相交但并不包含在目標之中,將區(qū)間進行二分操作豪诲,并把懶標記傳遞給兩個子區(qū)間(此時可能存在之前的標記)顶捷,清空當前區(qū)間的懶標記,最后繼續(xù)遞歸兩個子區(qū)間屎篱。

區(qū)間查詢

我們此處以查詢區(qū)間的最大值為例服赎,在遞歸查詢過程中,記當前節(jié)點為node交播,當前區(qū)間為[cl,cr]重虑,目標區(qū)間[l,r],我們會遇到三種情況:

  1. 當前區(qū)間與目標區(qū)間無交集秦士,此時遞歸結束缺厉,并返回0。
  2. 當前區(qū)間在目標區(qū)間之中隧土,此時遞歸結束芽死,并返回當前區(qū)間的值。
  3. 當前區(qū)間與目標區(qū)間相交但并不包含在目標之中次洼,此時再遞歸的向下進行查詢关贵,最后將兩個區(qū)間中的最大值返回。

代碼示例

Leetcode 731. 我的日程安排表 II為例卖毁,使用動態(tài)指針實現(xiàn)的動態(tài)開點的代碼為:

class MyCalendarTwo {

    class Node {
        int val, add;
        Node l, r;
    }

    int N = (int) 1e9 + 1;
    Node root;

    public MyCalendarTwo() {
        root = new Node();
    }

    public void update(Node node, int cl, int cr, int l, int r) {
        if (l <= cl && cr <= r) {
            node.add += 1;
            node.val += 1;
            return;
        }
        pushdown(node);
        int m = cl + cr >> 1;
        if (l <= m) update(node.l, cl, m, l, r);
        if (r > m) update(node.r, m + 1, cr, l, r);
        pushup(node);
    }

    public void pushdown(Node node) {
        if (node.l == null) node.l = new Node();
        if (node.r == null) node.r = new Node();
        node.l.add += node.add;
        node.l.val += node.add;
        node.r.add += node.add;
        node.r.val += node.add;
        node.add = 0;
    }

    public void pushup(Node node) {
        node.val = Math.max(node.l.val, node.r.val);
    }

    public boolean query(Node node, int cl, int cr, int l, int r) {
        if (l <= cl && cr <= r) return node.val < 2;
        pushdown(node);
        int m = cl + cr >> 1;
        if (l <= m && !query(node.l, cl, m, l, r)) return false;
        if (r > m && !query(node.r, m + 1, cr, l, r)) return false;
        return true;
    }

    public boolean book(int start, int end) {
        boolean ans = query(root, 0, N, start, end - 1);
        if (ans) update(root, 0, N, start, end - 1);
        return ans;
    }
}

遞歸過程:

線段樹-01.png

題目鏈接

  1. 699. 掉落的方塊
  2. 731. 我的日程安排表 II
  3. 732. 我的日程安排表 III
  4. 2276. 統(tǒng)計區(qū)間中的整數(shù)數(shù)目

參考文獻:

  1. 算法學習筆記(14): 線段樹
  2. 【宮水三葉】線段樹(動態(tài)開點)的兩種方式
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末揖曾,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子亥啦,更是在濱河造成了極大的恐慌炭剪,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件翔脱,死亡現(xiàn)場離奇詭異奴拦,居然都是意外死亡,警方通過查閱死者的電腦和手機届吁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進店門错妖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人疚沐,你說我怎么就攤上這事暂氯。” “怎么了亮蛔?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵痴施,是天一觀的道長。 經常有香客問我,道長辣吃,這世上最難降的妖魔是什么动遭? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮神得,結果婚禮上厘惦,老公的妹妹穿的比我還像新娘。我一直安慰自己循头,他們只是感情好,可當我...
    茶點故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布炎疆。 她就那樣靜靜地躺著卡骂,像睡著了一般。 火紅的嫁衣襯著肌膚如雪形入。 梳的紋絲不亂的頭發(fā)上全跨,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天,我揣著相機與錄音亿遂,去河邊找鬼浓若。 笑死,一個胖子當著我的面吹牛蛇数,可吹牛的內容都是我干的挪钓。 我是一名探鬼主播,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼耳舅,長吁一口氣:“原來是場噩夢啊……” “哼碌上!你這毒婦竟也來了?” 一聲冷哼從身側響起浦徊,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤馏予,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后盔性,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體霞丧,經...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年冕香,在試婚紗的時候發(fā)現(xiàn)自己被綠了蛹尝。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,932評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡悉尾,死狀恐怖箩言,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情焕襟,我是刑警寧澤陨收,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響务漩,放射性物質發(fā)生泄漏拄衰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一饵骨、第九天 我趴在偏房一處隱蔽的房頂上張望翘悉。 院中可真熱鬧,春花似錦居触、人聲如沸妖混。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽制市。三九已至,卻和暖如春弊予,著一層夾襖步出監(jiān)牢的瞬間祥楣,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工汉柒, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留误褪,地道東北人。 一個月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓碾褂,卻偏偏與公主長得像兽间,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子正塌,可洞房花燭夜當晚...
    茶點故事閱讀 44,884評論 2 354