Line tree learning materials

Keywords: C++

Preface:

Originally decided to learn data structure to learn things, the result has been Gu until now..

Line tree is a kind of advanced data structure.

It is a kind of binary tree, that is to say, for a line segment, we will use a binary tree to represent it.

Text:

Line tree can do single point query, single point modification, interval query, interval modification

Generally, line trees are

Let's give you an example

Now I have a string of numbers:

Put him in a line segment tree, and it will be like this:

Then the father of each leaf node is the sum of his son's values, which is a common line tree:

We mark each node with serial number in order:

We find that the serial number of each node's son is related to its own serial number - its own serial number is a, the left son's serial number 2a, and the right son's serial number 2a+1.
So, we can recursively build a line segment tree from the bottom up.

Definition

int input[500005];//An array used to hold input.
struct node{
    int l,r,sum;//l and r represent the range represented by the current node, and sum is the value of this node.
}tree[4*500005];//The space of the line tree should be opened to 4 times of the original array, otherwise it will die miserably.

Build up trees

void build(int i,int l,int r){//Recursive tree building, generally speaking, when calling, i's position is filled with 1, l and r are filled with the first sequence number and the last sequence number of the input array respectively.
   tree[i].l=l;tree[i].r=r;
   if(l==r){//If this node is a leaf node
       tree[i].sum=input[l];
       return ;
   }
   int mid=(l+r)>>1;
   build(i*2,l,mid);
   build(i*2+1,mid+1,r);//Construct left subtree and right subtree respectively
   tree[i].sum=tree[i*2].sum+tree[i*2+1].sum;//Then the son pushes it to the father.
    return ;
}

Next let's learn some basic operations

Interval modification

If this interval is completely included in the target interval, let's say that this interval marks k

Code

inline void add(int i,int l,int r,int k){
    if(tree[i].l>=l && tree[i].r<=r){//If this interval is completely included in the target interval, let's say that this interval marks k
        tree[i].sum+=k;
        return ;
    }
    if(tree[i*2].r>=l)
        add(i*2,l,r,k);
    if(tree[i*2+1].l<=r)
        add(i*2+1,l,r,k);
}

Single point query

The so-called single point query is to ask you what the current value of the * th number is after a meal of addition and subtraction.

Here's an example: I want to know the value of the fifth number now.

The following search is generated

The search is based on the scope of the node. If it happens to be this node, it will be output directly. If it is included in this node, continue refining.

Code

void search(int i,int dis){
    if(tree[i].l==tree[i].r) {
         return tree[i].sum;
    }
    int mid=(tree[i].l+tree[i].r)/2;
    if(dis<=mid) return search(i*2,dis);
    else return search(i*2+1,dis);
}

---------------------------------------------------Dividing line------------------------------------------------------------------------------

Interval query

Similar to a single point query, it can be understood as a single point query. Some nodes just contain this interval, which can be added directly.

Code

int search(int i,int l,int r){
    if(tree[i].l>=l&&tree[i].r<=r)
        return tree[i].sum;
    if(tree[i].r<l||tree[i].l>r) return 0;
    int s=0;
    if(tree[i*2].r>=1) s+=search(i*2,l,r);
    if(tree[i*2+1].l<=r) s+=search(i*2+1,l,r);
    return s;
}

Single point modification

We build the tree from the bottom to the top, and modify it from the top to the bottom when a single point is modified. As long as the nodes containing the target point are added with the same number, it is OK.

Code

inline void add(int i,int dis,int k){
    if(tree[i].l==tree[i].r){
        tree[i].sum+=k;
        return;
    }
    if(dis<=tree[i*2].r&&dis>=tree[i*2].l) tree[i].sum+=k,add(i*2,dis,k);
    else if(dis<=tree[i*2+1].r&&dis>=tree[i*2+1].l) tree[i].sum+=k,add(i*2+1,dis,k);
}

Note: the above interval modification and interval query cannot be shared. You will know why

Now we need to implement inter modification and interval query. If we put the above two together, there will be a problem. When the interval to be queried is not completely included in the modified interval, there will be a problem, so we need to use the lazy flag.

Principle: when the above situation occurs, first pass the lazy mark, and then judge.

Code (i.e. code of line tree template question 1)

void pushdown(ll i){
    if(tree[i].lazy!=0){
        tree[i*2].lazy+=tree[i].lazy;
        tree[i*2+1].lazy+=tree[i].lazy;
        ll mid=(tree[i].l+tree[i].r)/2;
        tree[i*2].num+=tree[i].lazy*(mid-tree[i*2].l+1);
        tree[i*2+1].num+=tree[i].lazy*(tree[i*2+1].r-mid);
        tree[i].lazy=0;
    }
    return ;
}
void add(ll i,ll l,ll r,ll k){
    if(tree[i].r<=r&&tree[i].l>=l) {
        tree[i].num+=k*(tree[i].r-tree[i].l+1);
        tree[i].lazy+=k;
        return;
    }
    pushdown(i);
    if(tree[i*2].r>=l)
        add(i*2,l,r,k);
    if(tree[i*2+1].l<=r)
        add(i*2+1,l,r,k);
    tree[i].num=tree[i*2].num+tree[i*2+1].num;
    return;
} 

ll search(ll i,ll l,ll r)
{
    if(tree[i].l>=l && tree[i].r<=r)
    return tree[i].num;
    if(tree[i].r<l||tree[i].l>r) return 0;
    pushdown(i);
    ll s=0;
    if(tree[i*2].r>=l) s+=search(i*2,l,r);
    if(tree[i*2+1].l<=r) s+=search(i*2+1,l,r);
    return s; 
}

Multiplication in line tree template 2

At this time, it can't be done like addition, because the order of operations is different with different operators.

This requires us to consider whether to add and multiply first or to multiply and add first when the lazy mark subscript is passed. We just need to do this for lazy tags.

There are two kinds of lazy markers, plz of addition and mlz of multiplication.

The code is similar to the above, with one more function

(line tree template question 2) code

 void pushdown(ll i){
    ll k1=tree[i].mlz,k2=tree[i].plz;
    tree[i<<1].sum=(tree[i<<1].sum*k1+k2*(tree[i<<1].r-tree[i<<1].l+1))%p;
    tree[i<<1|1].sum=(tree[i<<1|1].sum*k1+k2*(tree[i<<1|1].r-tree[i<<1|1].l+1))%p;
    tree[i<<1].mlz=(tree[i<<1].mlz*k1)%p;
    tree[i<<1|1].mlz=(tree[i<<1|1].mlz*k1)%p;
    tree[i<<1].plz=(tree[i<<1].plz*k1+k2)%p;
    tree[i<<1|1].plz=(tree[i<<1|1].plz*k1+k2)%p;
    tree[i].plz=0;
    tree[i].mlz=1;
    return ;
}
inline void mul(ll i,ll l,ll r,ll k){
    if(tree[i].r<l || tree[i].l>r)  return ;
    if(tree[i].l>=l && tree[i].r<=r){
        tree[i].sum=(tree[i].sum*k)%p;
        tree[i].mlz=(tree[i].mlz*k)%p;
        tree[i].plz=(tree[i].plz*k)%p;
        return ;
    }
    pushdown(i);
    if(tree[i<<1].r>=l)  mul(i<<1,l,r,k);
    if(tree[i<<1|1].l<=r)  mul(i<<1|1,l,r,k);
    tree[i].sum=(tree[i<<1].sum+tree[i<<1|1].sum)%p;
    return ;
}
void add(ll i,ll l,ll r,ll k){
    if(tree[i].r<l || tree[i].l>r)  return ;
    if(tree[i].l>=l && tree[i].r<=r){
        tree[i].sum+=((tree[i].r-tree[i].l+1)*k)%p;
        tree[i].plz=(tree[i].plz+k)%p;
        return ;
    }
    pushdown(i);
    if(tree[i<<1].r>=l)  add(i<<1,l,r,k);
    if(tree[i<<1|1].l<=r)  add(i<<1|1,l,r,k);
    tree[i].sum=(tree[i<<1].sum+tree[i<<1|1].sum)%p;
    return ;
}
ll search(ll i,ll l,ll r){
    if(tree[i].r<l || tree[i].l>r)  return 0;
    if(tree[i].l>=l && tree[i].r<=r)
        return tree[i].sum;
    pushdown(i);
    ll sum=0;
    if(tree[i<<1].r>=l)  sum+=search(i<<1,l,r)%p;
    if(tree[i<<1|1].l<=r)  sum+=search(i<<1|1,l,r)%p;
    return sum%p;
}

Finally, put the codes of the four template questions in place

Template tree array 1

#include<bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x) {
    x = 0;
    int f = 1;
    char ch = getchar();
    while (!isdigit(ch)) {
        if (ch == '-') f = -1;
        ch = getchar();
    }
    while (isdigit(ch)) {
        x = x * 10 + (ch ^ 48);
        ch = getchar();
    }
    x *= f;
    return;
}
template <typename T>
inline void write(T x)
{
    if(x < 0) {
        putchar('-');
        x = -x;
    }
    if(x > 9)
        write(x/10);
    putchar(x % 10 + '0');
    return;
}
int n,m,p;
int input[500005];
struct node{
    int l,r,sum;
}tree[4*500005];
inline void build(int i,int l,int r){
    tree[i].l=l,tree[i].r=r;
    if(l==r){
        tree[i].sum=input[l];
        return;
    }
    int mid=(l+r)>>1;
    build(i*2,l,mid);build(i*2+1,mid+1,r);
    tree[i].sum=tree[i*2].sum+tree[i*2+1].sum;
    return;
}
inline int search(int i,int l,int r){
    if(tree[i].l>=l&&tree[i].r<=r)
        return tree[i].sum;
    if(tree[i].r<l||tree[i].l>r) return 0;
    int s=0;
    if(tree[i*2].r>=1) s+=search(i*2,l,r);
    if(tree[i*2+1].l<=r) s+=search(i*2+1,l,r);
    return s;
}
inline void add(int i,int dis,int k){
    if(tree[i].l==tree[i].r){
        tree[i].sum+=k;
        return;
    }
    if(dis<=tree[i*2].r) add(i*2,dis,k);
    else add(i*2+1,dis,k);
    tree[i].sum=tree[i*2].sum+tree[i*2+1].sum;
}

int main(){
    int a,b,c,d;
    read(n),read(m);
    for(int i=1;i<=n;i++)
        read(input[i]);
    build(1,1,n);
    for(int i=1;i<=m;i++){
        read(a),read(b),read(c);
        if(a==1){
            add(1,b,c);
        }
        else{
            write(search(1,b,c)),cout<<endl;
        }
    }
}

Tree array 2 of template

#include<bits/stdc++.h>
using namespace std;
template <typename T>
void read(T &x) {
    x = 0;
    int f = 1;
    char ch = getchar();
    while (!isdigit(ch)) {
        if (ch == '-') f = -1;
        ch = getchar();
    }
    while (isdigit(ch)) {
        x = x * 10 + (ch ^ 48);
        ch = getchar();
    }
    x *= f;
    return;
}
template <typename T>
void write(T x)
{
    if(x < 0) {
        putchar('-');
        x = -x;
    }
    if(x > 9)
        write(x/10);
    putchar(x % 10 + '0');
    return;
}

int n,m,a,b,c,ans,f;
struct Tree{
    int l,r,num;
}tree[500005*4]; 
int input[500005];
inline void build(int i,int l,int r){
    tree[i].l=l,tree[i].r=r;
    if(l==r){
        tree[i].num=input[l];
        return;
    }
    int mid=(l+r)/2;
    build(i*2,l,mid);build(i*2+1,mid+1,r);
    tree[i].num=tree[i*2].num+tree[i*2+1].num;
}

inline void add(int i,int l,int r,int k)
{
    if(tree[i].l>=l&&tree[i].r<=r){
        tree[i].num+=k;
        return;
    }
    if(tree[i*2].r>=l)
        add(i*2,l,r,k);
    if(tree[i*2+1].l<=r)
        add(i*2+1,l,r,k);
}
inline void search(int i,int dis){//The code here is different from the one mentioned above, all of which are OK.
    ans+=tree[i].num;
    if(tree[i].l==tree[i].r) {
         return ;
    }
    int mid=(tree[i].l+tree[i].r)/2;
    if(dis<=mid) search(i*2,dis);
    if(dis>mid) search(i*2+1,dis);
}
int main(){
    read(n),read(m);
    build(1,1,n);
    for(int i=1;i<=n;i++)
        read(input[i]);
    for(int i=1;i<=m;i++)
    {
        read(f);
        if(f==1){
            read(a),read(b),read(c);
            add(1,a,b,c);
        }
        else{
            ans=0;
            read(a);
            search(1,a);
            cout<<ans+input[a]<<endl;
        }
        
    }
}

[template] line tree 1

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

template <typename T>
inline void read(T &x) {
    x = 0;
    ll f = 1;
    char ch = getchar();
    while (!isdigit(ch)) {
        if (ch == '-') f = -1;
        ch = getchar();
    }
    while (isdigit(ch)) {
        x = x * 10 + (ch ^ 48);
        ch = getchar();
    }
    x *= f;
    return;}
template <typename T>
inline void write(T x){
    if(x < 0) {
        putchar('-');
        x = -x;
    }
    if(x > 9)
        write(x/10);
    putchar(x % 10 + '0');
    return;
}

ll n,m,input[500005],a,b,c,d;
struct Tree{
    ll l,r,num,lazy;
}tree[500005*4];
inline void build(ll i,ll l,ll r){
    tree[i].l=l,tree[i].r=r;
    if(l==r){
        tree[i].num=input[l];
        return;
    }
    ll mid=(l+r)/2;
    build(i*2,l,mid);
    build(i*2+1,mid+1,r);
    tree[i].num=tree[i*2].num+tree[i*2+1].num;
}
inline void pushdown(ll i){
    if(tree[i].lazy!=0){
        tree[i*2].lazy+=tree[i].lazy;
        tree[i*2+1].lazy+=tree[i].lazy;
        ll mid=(tree[i].l+tree[i].r)/2;
        tree[i*2].num+=tree[i].lazy*(mid-tree[i*2].l+1);
        tree[i*2+1].num+=tree[i].lazy*(tree[i*2+1].r-mid);
        tree[i].lazy=0;
    }
    return ;
}
inline void add(ll i,ll l,ll r,ll k){
    if(tree[i].r<=r&&tree[i].l>=l) {
        tree[i].num+=k*(tree[i].r-tree[i].l+1);
        tree[i].lazy+=k;
        return;
    }
    pushdown(i);
    if(tree[i*2].r>=l)
        add(i*2,l,r,k);
    if(tree[i*2+1].l<=r)
        add(i*2+1,l,r,k);
    tree[i].num=tree[i*2].num+tree[i*2+1].num;
    return;
} 

inline ll search(ll i,ll l,ll r)
{
    if(tree[i].l>=l && tree[i].r<=r)
    return tree[i].num;
    if(tree[i].r<l||tree[i].l>r) return 0;
    pushdown(i);
    ll s=0;
    if(tree[i*2].r>=l) s+=search(i*2,l,r);
    if(tree[i*2+1].l<=r) s+=search(i*2+1,l,r);
    return s; 
}
int main(){
    read(n),read(m);
    for(register ll i=1;i<=n;i++)   
        read(input[i]);
    build(1,1,n);
    for(register ll i=1;i<=m;i++){
        read(d);
        if(d==1) read(a),read(b),read(c),add(1,a,b,c);
        else read(a),read(b),write(search(1,a,b)),cout<<'\n';
    }
} 

[template] line tree 2

#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll n,m,p;
ll input[100010];
struct node{
    ll l,r;
    ll sum,mlz,plz;
}tree[4*100010];
inline void build(ll i,ll l,ll r){
    tree[i].l=l;
    tree[i].r=r;
    tree[i].mlz=1;
    if(l==r){
        tree[i].sum=input[l]%p;
        return ;
    }
    ll mid=(l+r)>>1;
    build(i<<1,l,mid);
    build(i<<1|1,mid+1,r);
    tree[i].sum=(tree[i<<1].sum+tree[i<<1|1].sum)%p;
    return ;
}
inline void pushdown(ll i){
    ll k1=tree[i].mlz,k2=tree[i].plz;
    tree[i<<1].sum=(tree[i<<1].sum*k1+k2*(tree[i<<1].r-tree[i<<1].l+1))%p;
    tree[i<<1|1].sum=(tree[i<<1|1].sum*k1+k2*(tree[i<<1|1].r-tree[i<<1|1].l+1))%p;
    tree[i<<1].mlz=(tree[i<<1].mlz*k1)%p;
    tree[i<<1|1].mlz=(tree[i<<1|1].mlz*k1)%p;
    tree[i<<1].plz=(tree[i<<1].plz*k1+k2)%p;
    tree[i<<1|1].plz=(tree[i<<1|1].plz*k1+k2)%p;
    tree[i].plz=0;
    tree[i].mlz=1;
    return ;
}
inline void mul(ll i,ll l,ll r,ll k){
    if(tree[i].r<l || tree[i].l>r)  return ;
    if(tree[i].l>=l && tree[i].r<=r){
        tree[i].sum=(tree[i].sum*k)%p;
        tree[i].mlz=(tree[i].mlz*k)%p;
        tree[i].plz=(tree[i].plz*k)%p;
        return ;
    }
    pushdown(i);
    if(tree[i<<1].r>=l)  mul(i<<1,l,r,k);
    if(tree[i<<1|1].l<=r)  mul(i<<1|1,l,r,k);
    tree[i].sum=(tree[i<<1].sum+tree[i<<1|1].sum)%p;
    return ;
}
inline void add(ll i,ll l,ll r,ll k){
    if(tree[i].r<l || tree[i].l>r)  return ;
    if(tree[i].l>=l && tree[i].r<=r){
        tree[i].sum+=((tree[i].r-tree[i].l+1)*k)%p;
        tree[i].plz=(tree[i].plz+k)%p;
        return ;
    }
    pushdown(i);
    if(tree[i<<1].r>=l)  add(i<<1,l,r,k);
    if(tree[i<<1|1].l<=r)  add(i<<1|1,l,r,k);
    tree[i].sum=(tree[i<<1].sum+tree[i<<1|1].sum)%p;
    return ;
}
inline ll search(ll i,ll l,ll r){
    if(tree[i].r<l || tree[i].l>r)  return 0;
    if(tree[i].l>=l && tree[i].r<=r)
        return tree[i].sum;
    pushdown(i);
    ll sum=0;
    if(tree[i<<1].r>=l)  sum+=search(i<<1,l,r)%p;
    if(tree[i<<1|1].l<=r)  sum+=search(i<<1|1,l,r)%p;
    return sum%p;
}
int main(){
    scanf("%lld%lld%lld",&n,&m,&p);
    for(int i=1;i<=n;i++)  scanf("%lld",&input[i]);
    build(1,1,n); 
    for(int i=1;i<=m;i++){
        ll f1,a,b,c;
        scanf("%lld",&f1);
        if(f1==1)
            scanf("%lld%lld%lld",&a,&b,&c),mul(1,a,b,c);
        if(f1==2)
            scanf("%lld%lld%lld",&a,&b,&c),add(1,a,b,c);
        if(f1==3)
            scanf("%lld%lld",&a,&b),printf("%lld\n",search(1,a,b));
    }
    return 0;
}

Posted by legio on Thu, 19 Mar 2020 03:49:55 -0700