SegmentTree-Complete segment tree full version

Segment tree full version Keywords: lazy loading, lazy mark Lazy Tag

The case of single-point update is relatively simple. See the segment tree Basic Edition

Here to talk about the case update interval.

The scene is like this, or just the number, range and demand.


#define lson rt<<1
#define rson rt<<1|1
#define len (r-l+1) //(l,r)区间的长度

This is the update interval, we will use the interval length

Contribute

build and pushUp unchanged. We put the tree is set up to print it:

[1]:36 [2]:26 [3]:10 [4]:15 [5]:11 [6]:10 [7]:0 [8]:6 [9]:9 [10]:5 [11]:6 [12]:8 [13]:2 [14]:0

image-20181128195405878

pushDown focus

Lazy loading, lazy thinking mark:

Now, I assume in the interval [2,6] 5 number of full adder 10, the sum of the seek. Mathematics will all know, added a total of 50, the sum becomes 86. That unified operating period of the interval, the interval is no need to make changes in a single point.

Only changes to their ancestors, and to make a mark on their fathers . After losers need to use a son, a father to see marked on, I know this son also needs to be updated.

The following code is based on the father rt, and the corresponding interval length l, down pushDown lazy marker.

void pushDown(int rt,int len){//
    if(lazy[rt]){//这个点有lazyTag才往下下发lazyTag
                              //lazyTag里存的值是"要延迟加载的"值,例子就是10
        lazy[lson]+=lazy[rt];
        lazy[rson]+=lazy[rt];

        tree[lson]+=lazy[rt]*(len-len/2);//这里要注意
        tree[rson]+=lazy[rt]*(len/2);
        lazy[rt]=0;//清除父亲的标记
    }
}

Note that Line 6: an example will be described, rt representative interval [1,7], a length of 7,7 l / 2 = 3.

The [1,7]left and right sons [1,4]and [5,7]two. He left his son a length of 4, the right length of 3 sons.

Line 6 then write, is to deal with the interval length is odd, because it is a complete binary tree, interval left the son of a certain longer represented rt.

Update

void update(int L,int R,int addVal,int l,int r,int rt){
    cout<<__func__<<l<<','<<r<<','<<rt<<'n';
    //(l,r)就是根节点rt所代表的区间。
    //[L,R]是要更新的区间。
    if(L<=l&&R>=r){//(l,r)在[L,R]里
        tree[rt]+= len*addVal;//那就只更新rt,不用往下更新了。
        lazy[rt]+= addVal; //但必须做好lazy标记用于pushDown。标记的值就是要加的数。
        return;
    }
    //如果区间不能涵盖:
    pushDown(rt,r-l+1);//下放懒标记。防止以前有过改动儿子没加载
    int m = (l+r)>>1;
    if(L<=m)
        update(L,R,addVal,l,m,lson);
    if(R>m)
        update(L,R,addVal,m+1,r,rson);
    pushUp(rt);
}

By way of example we look at how the program is executed:

update(2,6,10,1,7,1);//2到6全加10

Print this:

update1,7,1
update1,4,2
update1,2,4
update2,2,9
update3,4,5
update5,7,3
update5,6,6
[0]:0 [1]:86 [2]:56 [3]:30 [4]:25 [5]:31 [6]:30 [7]:0 [8]:6 [9]:19 [10]:5 [11]:6 [12]:8 [13]:2 [14]:0 [15]:0 

Shown in the figure:image-20181128211645919

You can see, the box number, 5,6,8,2 although not updated, but their father is the correct value.

Inquire

We adopted the following query, look lazyTag in the end Shashi rafts handy.

Now we query interval (3,5) and number three, it should be 49.

Among them, the interval (3,4), although in the two numbers is 5, 6 and 31, but they are correct.

However, the number of 4 to 8 is not, and should be 18 fishes.

Look at the code:

int query(int L,int R,int l,int r, int rt){//[L,R]是要查询的区间
    cout<<__func__<<" ["<<L<<','<<R<<"] ("<<l<<','<<r<<") "<<rt<<'n';
    if(L<=l&&R>=r){//如果[L,R]里有(l,r)区间,直接返回对应的根节点
        return tree[rt];
    }
    pushDown(rt,len);//下放标记派上用场了
    int m = (l+r)>>1;
    int sum = 0;
    if(L<=m){
        sum += query(L,R,l,m,lson);
    }
    if(R>=m+1){
        sum += query(L,R,m+1,r,rson);
    }
    return sum;
}

Output:

query [3,5] (1,7) 1
query [3,5] (1,4) 2
query [3,5] (3,4) 5
query [3,5] (5,7) 3
query [3,5] (5,6) 6
pushDown rt:6 len:2
query [3,5] (5,5) 12
49

As we wish,

Line 5, the query interval (5,6), 6 do not belong to [3,5],

Performed down to pushDown (6), the sixth line is output pushDown rt:6 len:2.

If this time we re-print, you will find two 30 children 8 and 2 has been completed delay plus a large column  SegmentTree-Complete segment tree full version carrier, 18 and 12 to become

[1]:76 [2]:46 [3]:30 [4]:15 [5]:31 [6]:30 [7]:0 [8]:6 [9]:9 [10]:5 [11]:6 [12]:18 [13]:12 [14]:0

Segment tree full version

//线段树 求解区间最值问题
#include <iostream>
#include <vector>
#include "../Vt.h"

#define lson rt<<1
#define rson rt<<1|1
#define len (r-l+1)

using namespace std;

vector<int> vt{6,9,5,6,8,2,0};
int i = 0;
vector<int> tree(16);
vector<int> lazy(16);

void pushUp(int rt){
    tree[rt] = tree[lson]+tree[rson];
}

void build(int l,int r,int rt){
    if(l==r)//是叶节点,存数
    {
        tree[rt] = vt[i++];
        return;
    }
    int m = (l+r)>>1;
    build(l,m,lson);
    build(m+1,r,rson);
    pushUp(rt);
}

void pushDown(int rt,int l){
    if(lazy[rt]){//这个点有lazyTag才往下下发lazyTag
        cout<<__func__<<" rt:"<<rt<<" len:"<<l<<'n';
        lazy[lson]+=lazy[rt];
        lazy[rson]+=lazy[rt];

        tree[lson]+=lazy[rt]*(l-l/2);//这里要注意
        tree[rson]+=lazy[rt]*(l/2);
        lazy[rt]=0;
    }
}

void update(int L,int R,int addVal,int l,int r,int rt){
    cout<<__func__<<l<<','<<r<<','<<rt<<'n';
    //(l,r)就是根节点rt所代表的区间。
    //[L,R]是要更新的区间。
    if(L<=l&&R>=r){//(l,r)在[L,R]里
        tree[rt]+= len*addVal;//那就只更新rt,不用往下更新了。
        lazy[rt]+= addVal; //但必须做好lazy标记用于pushDown。标记的值就是要加的数。
        return;
    }
    //如果区间不能涵盖:
    pushDown(rt,r-l+1);//下放懒标记。防止以前有过改动儿子没加载
    int m = (l+r)>>1;
    if(L<=m)
        update(L,R,addVal,l,m,lson);
    if(R>=m+1)
        update(L,R,addVal,m+1,r,rson);
    pushUp(rt);
}

int query(int L,int R,int l,int r, int rt){//[L,R]是要查询的区间
    cout<<__func__<<" ["<<L<<','<<R<<"] ("<<l<<','<<r<<") "<<rt<<'n';
    if(L<=l&&R>=r){//如果[L,R]里有(l,r)区间,直接返回对应的根节点
        return tree[rt];
    }
    pushDown(rt,len);
    int m = (l+r)>>1;
    int sum = 0;
    if(L<=m){
        sum += query(L,R,l,m,lson);
    }
    if(R>=m+1){
        sum += query(L,R,m+1,r,rson);
    }
    return sum;
}

int main(){
    build(1,vt.size(),1);
    showVtwithIndex(tree);

    update(3,6,10,1,7,1);//3到6全加10
    showVtwithIndex(tree);

    cout << query(3,5,1,7,1)<<'n';
    showVtwithIndex(tree);
    return 0;
}

Guess you like

Origin www.cnblogs.com/liuzhongrong/p/11874776.html