Segment Tree(線段樹)

z26y25j10發表於2020-11-13

0.適用範圍

線段樹是一種資料結構,用於進行區間快速修改及查詢。

1.先導知識

二叉樹(略)

2.定義

線段樹的每個結點代表著一個區間,我們將這棵樹以陣列的方式儲存。

設一個下標為ID、代表區間[L,R]的結點,二分該結點,則該結點的左孩子(假如有的話)下標為2ID、代表區間[L,\frac{(L+R)}{2}];右孩子(假如有的話)下標為2ID+1、代表區間[\frac{(L+R)}{2}+1,R]

從線段樹的定義中可以發現,需要開大約4倍空間(或者說是大於等於n的最小的2的正數次冪*2)

3.lazy標誌

lazy標誌表示該下標對於該lazy值已計入計算,但其子節點還未用這個lazy值進行更新

因此需要使用pushDown函式實現lazy標誌的傳遞

void pushDown(int id)
{
    if(segTree[id].lazy)
    {
        int lid=id<<1,rid=id<<1|1;
        segTree[lid].lazy+=segTree[id].lazy;
        segTree[rid].lazy+=segTree[id].lazy;

        segTree[lid].val+=segTree[id].lazy*(segTree[lid].r-segTree[lid].l+1);
        segTree[rid].val+=segTree[id].lazy*(segTree[rid].r-segTree[rid].l+1);

        segTree[id].lazy=0;
    }
}//向下傳遞lazy

4.建樹

按照定義建樹即可

void pushUp(int id)
{
    segTree[id].val=segTree[id<<1].val+segTree[id<<1|1].val;
}//上推

void build(int l,int r,int id)
{
    segTree[id].l=l;
    segTree[id].r=r;
    if(l==r)
    {
        //-------------------------------------------------
        segTree[id].val=arr[l];
        //該區間是點,賦值為該點上的值
        //-------------------------------------------------
        return;
    }

    int m=(l+r)>>1;
    build(l,m,id<<1);
    build(m+1,r,id<<1|1);
    pushUp(id);
}//建樹

5.更新

void apply(int id,ll add)
{
    //-------------------------------------------------
    //視題目情況做操作
    segTree[id].val+=add*(segTree[id].r-segTree[id].l+1);
    segTree[id].lazy+=add;
    //此處為區間加
    //-------------------------------------------------
}//更新時具體需要做的操作

void update(int l,int r,int id,ll add)
{
    //-------------------------------------------------
    if(r<segTree[id].l||l>segTree[id].r) return;
    //該區間與要更新的區間不相交
    //-------------------------------------------------


    if(l<=segTree[id].l&&r>=segTree[id].r)
    {
        //-------------------------------------------------
        apply(id,add);
        return;
        //該區間整個包含於要更新的區間
        //-------------------------------------------------
    }
    pushDown(id);
    update(l,r,id<<1,add);
    update(l,r,id<<1|1,add);
    pushUp(id);
}//更新

6.查詢

ll query(int l,int r,int id)
{
    if(r<segTree[id].l||l>segTree[id].r) return 0;

    if(l<=segTree[id].l&&segTree[id].r<=r)
    {
        return segTree[id].val;
    }
    pushDown(id);

    ll ans=0;
    ans+=query(l,r,id<<1);
    ans+=query(l,r,id<<1|1);
    return ans;
}//查詢

 

相關文章