Notes on segment tree

Daily nonsense:

I do not know why there are persistent fascination of the tree line on the board water_lift, and just want to use water_lift board. (But forget water_lift how to write and then can not find a similar board can only pass with a company of the qwq)

 


Segment tree? What is:

Segment tree is a data structure used to maintain the interval period of a feature (such as minimum, sum, product ......) of the binary tree. The simplest application is probably the sum, minimum maintenance of a class, of course, complicated tree line so that you can not imagine.

Segment tree a few basic operations:

Order interval and the interval query, modify a single point, interval amended as eg

First to say, in fact, originally wanted to write a simple modification of the section will be fried, I will not result emm, so a direct increase lazy_tag.

Lazy_tag:

Delayed mark, if we modify the interval recursively to the leaf node, then making modifications, the complexity is O (mlogn), slower than simple, it is passed under the mark delay, when we do not use this sub-tree, do not need to be updated, only you need to make a mark on the roots, and then maintain the value of this root node. When using this subtree, then pass under.

Pretending all the basic operations have been written:

#include<bits/stdc++.h>
#define ll long longusingnamespace std;
inline ll read(){
    ll ans=0;
    char last='',ch=getchar();
    while(ch>'9'||ch<'0') last=ch,ch=getchar();
    while(ch>='0'&&ch<='9') ans=(ans<<1)+(ans<<3)+ch-'0',ch =

  getchar();
    if(last=='-') ans=-ans;
    return ans;
}
const ll N=100005;

ll n,m;
ll val[N];
ll sum[N*4],laz[N*4];

int main(){
    n=read();m=read();
    for(int i=1;i<=n;i++)
      val[i]=read();
    build(1,1,n);
    ll ops,x,y,k;
    for(int i=1;i<=m;i++){
        ops=read();x=read();y=read();
        if(ops==1){
            k=read();
            Add(1,1,n,x,y,k);
        }
        else printf("%lld\n",query(1,1,n,x,y));
    }
    return 0;
}

1. achievements;

"You write what ah?"

"Segment tree."

"Trees?"

The segment tree is not a tree without a soul, so the first step is obviously achievements; ( probably I will write a contribution )

Code achievements:

void build(ll node,ll x,ll y){
    if(x==y){
        sum[node]=val[x];
        return;
    }
    ll mid=x+y>>1;
    build(node<<1,x,mid);
    build(node<<1|1,mid+1,y);
    sum[node]=sum[node<<1]+sum[node<<1|1];
}

explain:

ll node represents the current node to build number, ll x represents the left end of this range, ll y represents the right end of this section;

When x == y, that is, leaf nodes, very easy to know the sum of this node is the value of its own.

Since then segment tree is very strict binary tree, so its numbers are determined for each son, namely node * 2 and node * 2 + 1; therefore recursive achievements of the last maintenance interval and the like;

2. range query:

First on the code:

LL Query (LL Node, LL L, LL R & lt, LL X, LL Y) {
     IF (L> = X && R & lt <= Y) // recursively to the section is completely contained in the queried interval 
      return SUM [Node]; 
    LL MID = L + R & lt >> . 1 ; 
    LL RES = 0 ; 
pushdown (Node, L, R & lt, MID);
IF (X <= MID ) = RES + Query (Node <<. 1 , L, MID, X, Y); IF (MID < Y) = RES + Query (Node << . 1 | . 1 , MID + . 1 , R & lt, X, Y); return RES; }

Explanation wave:

Because the query must be the beginning of a query from 1 ~ n, then recursive queries. So when recursion to be included in a full range of the number to be queried, obviously can not continue down recursive, because this point has been maintained during this interval and the direct return can; then determine the midpoint of the interval, if there is clear :

x <= mid of the case, it means that we can query interval to a son node in the left (we can not determine the size of the interval, the son may be left whole, it could be a leaf left his son), then you need son left to seek recursive

 y> mid case, it means that a certain sons included in the right part in the interval [x, y] in the right son so recursively;

 The son then left and right son recursive add up to the value that we want to query interval and;

3. Single-point modification (does not need to write and learning)

CODE:

void Change (Node LL, LL L, R & lt LL, LL x, V LL) { // à plus V 
    IF (R & lt <L || x> x) return ; // when the value of the right to modify the interval ratio of x to hours, with no apparent recursive section and right
     // left section Similarly 
    IF (R & lt && L == L == X) { 
        SUM [Node] + = V;
         return ; 
    } 
    LL MID = L + R & lt >> . 1 ; 
    Change (Node << . 1 | . 1 , MID + . 1 , R & lt, X, V); 
    Change (Node << . 1 , L, MID, X, V); 
    SUM [Node] = SUM [Node << . 1 ] + SUM [<< Node 1 |1]; 
}

Explanation wave ~

First, determine the solvability of the case can not: the most right-recursive than to the interval x h

Clearly then recursion can not find the solution, so a direct return Well;

Also when the most left recursive interval is greater than x, apparently it does not work:

So in both cases the direct return;

When the recursion we need to modify x: Modify the corresponding sum value returned.

Then for x but is not required to modify the interval x included, find it's about our son are recursive, and finally re-value sum of maintenance;

4. Modify interval:

First on the code ++:

void add(ll node,ll l,ll r,ll k){
    laz[node]+=k;
    sum[node]+=(r-l+1)*k; 
}
void pushdown(ll node,ll l,ll r,ll mid){
    if(laz[node]==0) return;
    add(node<<1,l,mid,laz[node]);
    add(node<<1|1,mid+1,r,laz[node]);
    laz[node]=0;
}

void Add(ll node,ll l,ll r,ll x,ll y,ll k){
    if(x<=l&&y>=r) return add(node,l,r,k);
    ll mid=l+r>>1;
    pushdown(node,l,r,mid);
    if(x<=mid) Add(node<<1,l,mid,x,y,k);
    if(y>mid) Add(node<<1|1,mid+1,r,x,y,k);
    sum[node]=sum[node<<1]+sum[node<<1|1];
} 

I started to explain:

First determine if the current interval recursive entirely contained in the interval [x, y] in this range directly for the add operation, maintenance interval and this interval, then hit lazy_tag;

 

Then still corresponding respectively recursive son left and right son, still need to determine whether the corresponding recursion. Do not forget maintenance intervals and.

Then do not thoroughly understand why at this time to pushdown.

 pushdown is downstream of the marking process;


CODE:

#include<bits/stdc++.h>
#define ll long long
const int N=100005;

using namespace std;

inline ll read(){
    int ans=0;
    char last=' ',ch=getchar();
    while(ch>'9'||ch<'0') last=ch,ch=getchar();
    while(ch<='9'&&ch>='0') ans=(ans<<3)+(ans<<) + ch-1'0',ch=getchar();
    if(last=='-') ans=-ans;
    return ans;
}

ll n,m;
ll val[N],sum[N*4],laz[N*4];

void build(ll node,ll x,ll y){//建树
    if(x==y){
        sum[node]=val[x];
        return;
    }
    ll mid=x+y>>1;
    build(node<<1,x,mid);
    build(node<<1|1,mid+1,y);
    sum[node]=sum[node<<1]+sum[node<<1|1];
}

void add(ll node,ll l,ll r,ll k){//添加维护 
    laz[node]+=k;
    sum[node]+=(r-l+1)*k; 
}
void pushdown(ll node,ll l,ll r,ll mid){//标记下传 
    if(laz[node]==0) return;
    add(node<<1,l,mid,laz[node]);
    add(node<<1|1, MID + . 1 , R & lt, Laz [Node]); 
    Laz [Node] = 0 ; 
} 

LL Query (LL Node, LL L, LL R & lt, LL X, LL Y) { // query 
    IF (L> = X && R & lt <= Y) // recursive interval to be completely contained in the query interval 
      return SUM [Node]; 
    LL MID = L + R & lt >> . 1 ; 
    LL RES = 0 ; 
    pushdown (Node, L, R & lt, MID); 
    IF ( MID <= X) RES + = Query (Node << . 1 , L, MID, X, Y);
     IF (MID> Y) RES + = Query (Node << . 1 | . 1 , MID + . 1 , R & lt, X, Y);
     return RES; 
} 

voidChange (Node LL, LL L, R & lt LL, LL x, V LL) { // à plus V 
    IF (R & lt <L || x> x) return ; // when the right to modify the value of the interval for ratio of x hours, with no apparent recursive section and right
     // left section Similarly 
    IF (R & lt && L == L == X) { 
        SUM [Node] + = V;
         return ; 
    } 
    LL MID = L + R & lt >> . 1 ; 
    Change (Node < < . 1 | . 1 , MID + . 1 , R & lt, X, V); 
    Change (Node << . 1 , L, MID, X, V); 
    SUM [Node] = SUM [Node << . 1 ] + SUM [Node << . 1 | 1]; 
}

void Add(ll node,ll l,ll r,ll x,ll y,ll k){//区间加k 
    if(x<=l&&y>=r) return add(node,l,r,k);
    ll mid=l+r>>1;
    pushdown(node,l,r,mid);
    if(x<=mid) Add(node<<1,l,mid,x,y,k);
    if(y>mid) Add(node<<1|1,mid+1,r,x,y,k);
    sum[node]=sum[node<<1]+sum[node<<1|1];
} 

int main(){
    n=read();m=read();
    for(ll i=1;i<=n;i++) val[i]=read();
    build(1,1,n);
    int ops;
    ll x,y,k;
    for(ll i=1;i<=m;i++){
        ops=read(); x=read();y=read();
        if(ops==1){
            k=read();
            Add(1,1,n,x,y,k);
        }
        else printf("%lld",query(1,1,n,x,y));
    }
    return 0;
}

To the attention of open space to open four times a sequence of length N, why I was not very clear, anyway, it can not be opened twice.

Well, no

end-

 

Guess you like

Origin www.cnblogs.com/zhuier-xquan/p/11107100.html