亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Go語言實(shí)現(xiàn)動態(tài)開點(diǎn)線段樹詳解

 更新時(shí)間:2025年02月26日 08:15:41   作者:MelonTe  
線段樹是一種用于高效處理區(qū)間查詢和區(qū)間更新的數(shù)據(jù)結(jié)構(gòu),下面我們就來看看如何使用Go實(shí)現(xiàn)動態(tài)開點(diǎn)線段樹的方式,感興趣的可以了解下

1、線段樹介紹

線段樹是一種用于高效處理區(qū)間查詢和區(qū)間更新的數(shù)據(jù)結(jié)構(gòu),當(dāng)我們需要解決一個頻繁更新區(qū)間值的問題的時(shí)候,就可以采用線段樹的結(jié)構(gòu)進(jìn)行解決。線段樹的核心思想是將區(qū)間分為多個子區(qū)間進(jìn)行管理,越往下區(qū)間范圍越小,根節(jié)點(diǎn)表示整個線段樹能表示的區(qū)間。

本文記錄使用Go實(shí)現(xiàn)動態(tài)開點(diǎn)線段樹的方式,該模板的線段樹用于解決區(qū)間求和問題,還有求解區(qū)間最小值、最大值的線段樹可以進(jìn)行微調(diào)修改即可。

區(qū)間查詢、區(qū)間更新的時(shí)間復(fù)雜度均為O(logN)。

2、動態(tài)開點(diǎn)線段樹實(shí)現(xiàn)

動態(tài)開點(diǎn)的核心在于,需要縮小范圍,即進(jìn)入子節(jié)點(diǎn)的時(shí)候再進(jìn)行創(chuàng)建,相對于使用數(shù)組來實(shí)現(xiàn)線段樹,可以更大的減小空間開銷。

線段樹節(jié)點(diǎn)

一個節(jié)點(diǎn)需要記錄它的左子節(jié)點(diǎn)、右子節(jié)點(diǎn)、當(dāng)前節(jié)點(diǎn)表示的區(qū)間的和val,以及暫未下推給子節(jié)點(diǎn)的懶惰值lazy。

type SegTreeNode struct {
    lazy  int
    val   int
    left  *SegTreeNode
    right *SegTreeNode
}

線段樹的創(chuàng)建

整個線段樹只需要記錄一個根節(jié)點(diǎn)以及該線段樹表示的區(qū)間上屆。

type SegTree struct {
    //線段樹的范圍,0~N
    N    int
    root *SegTreeNode
}
 
// 創(chuàng)建線段樹
func CreateSegTree(n int) *SegTree {
    return &SegTree{
        N: n,
        root: &SegTreeNode{
            lazy:  0,
            val:   0,
            left:  nil,
            right: nil,
        },
    }
}

遞歸上推

當(dāng)更新完了子節(jié)點(diǎn)后,回到當(dāng)前節(jié)點(diǎn)的時(shí)候,需要更新當(dāng)前節(jié)點(diǎn)的值,表示從樹的底部上推值。

// 遞歸上推
func (ST *SegTree) Pushup(node *SegTreeNode) {
    node.val = node.left.val + node.right.val
}

懶惰下推

當(dāng)需要縮小查找區(qū)間的時(shí)候,需要向下查找,這時(shí)候要先把懶惰值下推,防止查找出錯誤的結(jié)果,也防止子節(jié)點(diǎn)還未創(chuàng)建。

// 同步下推
func (ST *SegTree) Pushdown(node *SegTreeNode, leftnum, rightnum int) {
    //創(chuàng)建左右節(jié)點(diǎn)
    if node.left == nil {
        node.left = new(SegTreeNode)
    }
    if node.right == nil {
        node.right = new(SegTreeNode)
    }
    //下推節(jié)點(diǎn)懶惰標(biāo)記
    if node.lazy == 0 {
        return
    }
    node.left.val += leftnum * node.lazy
    node.right.val += rightnum * node.lazy
    //下推
    node.left.lazy += node.lazy
    node.right.lazy += node.lazy
    //置零
    node.lazy = 0
}

首先先創(chuàng)建左右節(jié)點(diǎn),如果沒有需要下推的懶惰標(biāo)記則直接返回。否則就更新左右節(jié)點(diǎn)的val和lazy。

更新操作

// 更新操作,更新[left,right]區(qū)間的值,start和end是當(dāng)前處在區(qū)間
func (ST *SegTree) Update(node *SegTreeNode, start, end, left, right, val int) {
    if left <= start && end <= right {
        //鎖定區(qū)間,進(jìn)行更新
        node.val += (end - start + 1) * val
        node.lazy += val
        return
    }
    //縮小區(qū)間
    mid := (start + end) / 2
    //需要找到子節(jié)點(diǎn),先下推懶惰標(biāo)記
    ST.Pushdown(node, mid-start+1, end-mid)
    if mid >= left {
        ST.Update(node.left, start, mid, left, right, val)
    }
    if mid+1 <= right {
        ST.Update(node.right, mid+1, end, left, right, val)
    }
    //遞歸
    ST.Pushup(node)
}

left和right表示要更新的區(qū)間,而start和end表示當(dāng)前區(qū)間。如果當(dāng)前區(qū)間處在需要更新的區(qū)間內(nèi),則直接更新區(qū)間值以及懶惰值,然后直接返回即可,此時(shí)不需要繼續(xù)更新下面節(jié)點(diǎn)的值,這是動態(tài)開點(diǎn)的關(guān)鍵所在。

若當(dāng)前區(qū)間并未完全處在需要更新的區(qū)間內(nèi),則二分該區(qū)間,縮小范圍進(jìn)行更新。

例如在一次操作需要更新的是[30,40]范圍的值,而當(dāng)前區(qū)間處在[25,50]中,當(dāng)前區(qū)間并未完全處在更新區(qū)間,則二分為[25,37]和[38,50],左區(qū)間和右區(qū)間均和需要更新的區(qū)間存在交集,那么就往下更新,直到更新區(qū)間包含當(dāng)前區(qū)間。

在更新完后,進(jìn)行一次上推。

查詢操作

與更新操作類似,只需要一個ans來記錄答案并且返回。

// 查詢操作,返回區(qū)間的值
func (ST *SegTree) Query(node *SegTreeNode, start, end, left, right int) int {
    if left <= start && end <= right {
        return node.val
    }
    mid := (start + end) / 2
    ST.Pushdown(node, mid-start+1, end-mid)
    ans := 0
    if left <= mid {
        ans += ST.Query(node.left, start, mid, left, right)
    }
    if mid+1 <= right {
        ans += ST.Query(node.right, mid+1, end, left, right)
    }
    return ans
}

到此這篇關(guān)于Go語言實(shí)現(xiàn)動態(tài)開點(diǎn)線段樹詳解的文章就介紹到這了,更多相關(guān)Go線段樹內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • go-cqhttp環(huán)境配置及安裝過程

    go-cqhttp環(huán)境配置及安裝過程

    這篇文章主要介紹了go-cqhttp環(huán)境配置,包括go-cqhttp安裝及簡單介紹,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-09-09
  • Go語言中三個輸入函數(shù)(scanf,scan,scanln)的區(qū)別解析

    Go語言中三個輸入函數(shù)(scanf,scan,scanln)的區(qū)別解析

    本文詳細(xì)介紹了Go語言中三個輸入函數(shù)Scanf、Scan和Scanln的區(qū)別,包括用法、功能和輸入終止條件等,本文給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2024-10-10
  • Go簡單實(shí)現(xiàn)協(xié)程方法

    Go簡單實(shí)現(xiàn)協(xié)程方法

    本文主要介紹了Go簡單實(shí)現(xiàn)協(xié)程的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-12-12
  • go語言切片去重的3種方式

    go語言切片去重的3種方式

    go語言中的切片是使用非常頻繁的一個數(shù)據(jù)結(jié)構(gòu),本文主要介紹了go語言切片去重的3種方式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-08-08
  • Go語言異常處理error、panic、recover的使用

    Go語言異常處理error、panic、recover的使用

    GO語言中引入的異常的處理方式為error、panic、recover ,本文主要介紹了Go語言異常處理error、panic、recover的使用,感興趣的可以了解一下
    2024-08-08
  • 淺談Golang內(nèi)存逃逸

    淺談Golang內(nèi)存逃逸

    本文主要介紹了Golang內(nèi)存逃逸,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • go語言編程實(shí)現(xiàn)遞歸函數(shù)示例詳解

    go語言編程實(shí)現(xiàn)遞歸函數(shù)示例詳解

    這篇文章主要為大家介紹了go語言編程實(shí)現(xiàn)遞歸函數(shù)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09
  • Golang Cron 定時(shí)任務(wù)的實(shí)現(xiàn)示例

    Golang Cron 定時(shí)任務(wù)的實(shí)現(xiàn)示例

    這篇文章主要介紹了Golang Cron 定時(shí)任務(wù)的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • go json編譯原理XJSON實(shí)現(xiàn)四則運(yùn)算

    go json編譯原理XJSON實(shí)現(xiàn)四則運(yùn)算

    這篇文章主要為大家介紹了go json編譯原理XJSON實(shí)現(xiàn)四則運(yùn)算示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07
  • go語言面試如何實(shí)現(xiàn)自旋鎖?

    go語言面試如何實(shí)現(xiàn)自旋鎖?

    這篇文章主要為大家介紹了go語言面試中常問的如何實(shí)現(xiàn)自旋鎖問題實(shí)例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11

最新評論