Segment tree template + some of my own understanding

After reading it many times, I finally understand something

Because the left and right child nodes are often used, first define two functions to calculate the serial numbers of the left and right children:

inline lc(int x){return x<<1;}  //Left son
inline rc(int x){return x<<1|1;}//Right son

First, the segment tree uses each node of the binary tree to represent an interval, the top node represents the whole interval, and then the next layer represents half of the nodes of the previous layer. In this way, one layer is divided into two layers until the bottom leaf node.
So let's first look at the tree building code:

void build(int p,int l,int r)   //Build a tree
{
    if(l==r){
        t[p]=a[l];
        return ;
    }
    int mid=(l+r)>>1;
    build(lc(p),l,mid);
    build(rc(p),mid+1,r);
    up(p);
}

This is a recursive process. It divides from top to bottom until the leaf node (l==r) is equal to the corresponding number in the original array. Then, every time the tree is split down, because the value of the node of the tree changes, its parent node will also change. Therefore, after each downward recursion, it must be updated upward, which is the up() function:

void up(int p)  //Update tree up
{
    //t[p]=max(t[lc(p)],t[rc(p)]); // Maintain maximum value
    t[p]=t[lc(p)]+t[rc(p)];     //Maintenance and
}

Then say the lazy mark
When updating the segment tree, the nodes need to be from top to bottom. If n values are modified, many nodes will be updated. However, sometimes not all updated nodes will be used, so lazy tags are used to save operations. Lazy tag means that when a node in the tree needs to be changed, it is marked with a lazy tag. The value of the lazy tag is the change amount. Then the node is updated, and then it will not be updated. After each update or query operation, the next level will be updated. This means that the node is updated only when it needs to be used, otherwise it will not be updated. Here, lazy [] array is used for lazy tag, and down() function is used for downward update:

void down(int p,int l,int r)    //Lazy mark Download
{
    if(lazy[p]){	//First, judge whether to update downward
        //Lazy mark Download
        lazy[lc(p)]+=lazy[p];
        lazy[rc(p)]+=lazy[p];
        //Update the two child nodes of the next layer
        int mid=(l+r)>>1;
        t[lc(p)]+=lazy[p]*(mid-l+1);
        t[rc(p)]+=lazy[p]*(r-mid+1);
        //The current layer is marked as 0
        lazy[p]=0;
    }
}

After that, update with lazy tag:

void update(int xl,int xr,int x,int p,int l,int r)
{//XL and XR are the intervals to be modified
 //x is the variable value
 //p is the current node number
 //l. R is the current interval
    if(xl<=l && xr>=r){
        //t[p]=x;
        lazy[p]+=x; //The node governing the current interval is marked with lazy flag
        t[p]+=x*(r-l+1);    //Modify nodes on the tree
        return ;
    }
    down(p,l,r);    //Next pass lazy flag
    int mid=(l+r)>>1;
    if(xl<=mid) update(xl,xr,x,lc(p),l,mid);
    if(xr>mid) update(xl,xr,x,rc(p),mid+1,r);
    up(p);  //Up update maintenance
}

Query operation:

int query(int xl,int xr,int l,int r,int p)
{//XL and XR are the intervals to be modified
 //l. R is the current interval
 //p is the current node number
    if(xl<=l && r<=xr) return t[p];
    down(p,l,r);    //Lazy mark next level
    int mid=(l+r)>>1;
    int ans=0;
    if(xl<=mid){
        //ans=max(query(xl,xr,l,mid,lc(p)),ans);    // Operation of querying the latest value
        ans+=query(xl,xr,l,mid,lc(p));
    }
    if(xr>mid){
        //ans=max(query(xl,xr,mid+1,r,rc(p)),ans);
        ans+=query(xl,xr,mid+1,r,rc(p));
    }
    return ans;
}

Then you can spell it
Take hdoj's 1166 as an example:

#include <bits/stdc++.h>
using namespace std;

#define rg register
#define putln putchar('\n')
#define debug(x) cout<<"@ "<<(x)<<endl
#define rep(i,a,b) for(rg int i=a;i<=b;++i)
#define per(i,a,b) for(rg int i=a;i>=b;--i)

typedef long long ll;
const int MXN = 2e5+5;
int a[MXN];
int t[4*MXN],lazy[4*MXN]; //t is the tree and lazy is the lazy flag
int n,m,l,r,p;
string s;
inline lc(int x){return x<<1;}  //Left son
inline rc(int x){return x<<1|1;}//Right son

void up(int p)  //Update tree up
{
    //t[p]=max(t[lc(p)],t[rc(p)]); // Maintain maximum value
    t[p]=t[lc(p)]+t[rc(p)];     //Maintenance and
}
void down(int p,int l,int r)    //Lazy mark Download
{
    if(lazy[p]){
        //Lazy mark Download
        lazy[lc(p)]+=lazy[p];
        lazy[rc(p)]+=lazy[p];
        //Update the two child nodes of the next layer
        int mid=(l+r)>>1;
        t[lc(p)]+=lazy[p]*(mid-l+1);
        t[rc(p)]+=lazy[p]*(r-mid+1);
        //The current layer is marked as 0
        lazy[p]=0;
    }
}
void build(int p,int l,int r)   //Build a tree
{
    if(l==r){
        t[p]=a[l];
        return ;
    }
    int mid=(l+r)>>1;
    build(lc(p),l,mid);
    build(rc(p),mid+1,r);
    up(p);
}
void update(int xl,int xr,int x,int p,int l,int r)
{//XL and XR are the intervals to be modified
 //x is the variable value
 //p is the current node number
 //l. R is the current interval
    if(xl<=l && xr>=r){
        //t[p]=x;
        lazy[p]+=x; //The node governing the current interval is marked with lazy flag
        t[p]+=x*(r-l+1);    //Modify nodes on the tree
        return ;
    }
    down(p,l,r);    //Next pass lazy flag
    int mid=(l+r)>>1;
    if(xl<=mid) update(xl,xr,x,lc(p),l,mid);
    if(xr>mid) update(xl,xr,x,rc(p),mid+1,r);
    up(p);  //Up update maintenance
}
int query(int xl,int xr,int l,int r,int p)
{//XL and XR are the intervals to be modified
 //l. R is the current interval
 //p is the current node number
    if(xl<=l && r<=xr) return t[p];
    down(p,l,r);    //Lazy mark next level
    int mid=(l+r)>>1;
    int ans=0;
    if(xl<=mid){
        //ans=max(query(xl,xr,l,mid,lc(p)),ans);    // Operation of querying the latest value
        ans+=query(xl,xr,l,mid,lc(p));
    }
    if(xr>mid){
        //ans=max(query(xl,xr,mid+1,r,rc(p)),ans);
        ans+=query(xl,xr,mid+1,r,rc(p));
    }
    return ans;
}
int main()
{
    scanf("%d",&p);
    rep(i,1,p){
        memset(t,0,sizeof(t));
        memset(lazy,0,sizeof(lazy));
        scanf("%d",&n);
        rep(j,1,n) scanf("%d",&a[j]);
        build(1,1,n);
        printf("Case %d:\n",i);
        while(cin>>s&&s!="End"){
            scanf("%d %d",&l,&r);
            if(s=="Query") printf("%d\n",query(l,r,1,n,1));
            if(s=="Add") update(l,l,r,1,1,n);
            if(s=="Sub") update(l,l,-r,1,1,n);
        }
    }
    return 0;
}

Tags: Algorithm data structure

Posted on Fri, 24 Sep 2021 08:37:21 -0400 by metrostars