线段树模板

定义
线段树是一种特殊的二叉树,每个节点代表原数组的一段区间,根节点代表整个区间,叶节点代表长度为1的区间。
一般应用:
利用线段树快速求区间的最值,求和等。
使用延迟标记可以很好地支持区间修改。
单次修改和查询的时间复杂度都是O(log n)。
一:

题目描述

如题,已知一个数列,你需要进行下面两种操作:

1.将某区间每一个数加上x

2.求出某区间每一个数的和
输入输出格式
输入格式:

第一行包含两个整数N、M,分别表示该数列数字的个数和操作的总个数。

第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。

接下来M行每行包含3或4个整数,表示一个操作,具体如下:

操作1: 格式:1 x y k 含义:将区间[x,y]内每个数加上k

操作2: 格式:2 x y 含义:输出区间[x,y]内每个数的和

输出格式:

输出包含若干行整数,即为所有操作2的结果。

输入输出样例
输入样例#1: 复制

5 5
1 5 4 2 3
2 2 4
1 2 3 2
2 3 4
1 1 5 1
2 1 4

输出样例#1: 复制

11
8
20

说明

时空限制:1000ms,128M

数据规模:

对于30%的数据:N<=8,M<=10

对于70%的数据:N<=1000,M<=10000

对于100%的数据:N<=100000,M<=100000

(数据已经过加强^_^,保证在int64/long long数据范围内)

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=100005;
ll n,m,a[maxn];
int cnt,rt;
struct Node{      
    ll sum;  //sum代表此区间的值。
    int lazy;  //lazy表示延迟标记,修改区间值时需要用到
    int l,r;   //左右区间
    int ls,rs;  //左右儿子
}node[maxn*2];
inline void pushup(ll x){     //求值更新区间
    ll lson=node[x].ls,rson=node[x].rs;
    node[x].sum=node[lson].sum+node[rson].sum;  //求值
    node[x].l=node[lson].l;   //更新区间
    node[x].r=node[rson].r;
}
inline void pushdown(ll x){      //标记下放
    ll lson=node[x].ls,rson=node[x].rs;
    node[lson].sum+=node[x].lazy*(node[lson].r-node[lson].l+1);
    node[rson].sum+=node[x].lazy*(node[rson].r-node[rson].l+1);
    node[lson].lazy+=node[x].lazy;
    node[rson].lazy+=node[x].lazy;
    node[x].lazy=0;    //标记还原
}
inline void build(ll L,ll R,ll cur){     //建树
    if(L==R){    //如果是叶节点
        node[cur].ls=node[cur].rs=-1;    //没有儿子
        node[cur].l=node[cur].r=L;
        node[cur].sum=a[L];
        node[cur].lazy=0;
        return;
    }
    ll mid=(L+R)/2;
    node[cur].ls=++cnt,node[cur].rs=++cnt;
    build(L,mid,node[cur].ls);         //递归建树
    build(mid+1,R,node[cur].rs);
    pushup(cur);          //更新区间lazy
}
inline ll query(ll L,ll R,ll cur){         //求和函数
    if(L<=node[cur].l && node[cur].r<=R)
        return node[cur].sum;     //在所求区间内
    pushdown(cur);       //标记下放
    ll tot=0;
    ll mid=(node[cur].l+node[cur].r)/2;
    if(L<=mid)  tot+=query(L,R,node[cur].ls);   //区间落在左子树
    if(mid<R)   tot+=query(L,R,node[cur].rs);   //区间落在右子树
    return tot;
}
inline void update(ll L,ll R,ll c,ll cur){   //修改区间   
    if(L<=node[cur].l && node[cur].r<=R){   //落在区间内
        node[cur].sum+=c*(node[cur].r-node[cur].l+1);
        node[cur].lazy+=c;
        return; 
    }
    pushdown(cur);  //标记下放
    ll mid=(node[cur].l+node[cur].r)/2;
    if(L<=mid)  update(L,R,c,node[cur].ls);
    if(mid<R)   update(L,R,c,node[cur].rs);
    pushup(cur);   //修改子树
}
int main(){
    scanf("%lld%lld",&n,&m);
    for(register int i=1;i<=n;i++)
        scanf("%lld",&a[i]);    
    rt=++cnt;    //根节点编号为1
    build(1,n,rt);     //建树
    for(register int i=1;i<=m;i++){
        ll x;
        scanf("%lld",&x);
        if(x==1){
            ll aa,bb,cc;
            scanf("%lld%lld%lld",&aa,&bb,&cc);
            update(aa,bb,cc,rt);
        } 
        else{
            ll aa,bb;
            scanf("%lld%lld",&aa,&bb);
            printf("%lld
",query(aa,bb,rt));
        }
    }
    return 0;
}

二:

题目描述

如题,已知一个数列,你需要进行下面三种操作:

1.将某区间每一个数乘上x

2.将某区间每一个数加上x

3.求出某区间每一个数的和
输入输出格式
输入格式:

第一行包含三个整数N、M、P,分别表示该数列数字的个数、操作的总个数和模数。

第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。

接下来M行每行包含3或4个整数,表示一个操作,具体如下:

操作1: 格式:1 x y k 含义:将区间[x,y]内每个数乘上k

操作2: 格式:2 x y k 含义:将区间[x,y]内每个数加上k

操作3: 格式:3 x y 含义:输出区间[x,y]内每个数的和对P取模所得的结果

输出格式:

输出包含若干行整数,即为所有操作3的结果。

输入输出样例
输入样例#1: 复制

5 5 38
1 5 4 2 3
2 1 4 1
3 2 5
1 2 4 2
2 3 5 5
3 1 4

输出样例#1: 复制

17
2

说明

时空限制:1000ms,128M

数据规模:

对于30%的数据:N<=8,M<=10

对于70%的数据:N<=1000,M<=10000

对于100%的数据:N<=100000,M<=100000

(数据已经过加强^_^)

    此题要定义一个加法lazy标记和乘法lazy标记,更新时如果是乘法
,就将加法标记同乘。其余和第一个模板类似。
#include<bits/stdc++.h>
#define maxn 100005
#define ll long long
using namespace std;
ll n,m,cnt,rt,p;
ll a[maxn];
struct Node{
    ll sum;
    ll add_lazy,mul_lazy;
    ll l,r;
    ll ls,rs;
};
Node node[2*maxn];
inline void pushup(ll x){
     ll lson=node[x].ls;
     ll rson=node[x].rs;
     node[x].sum=node[lson].sum+node[rson].sum;
     node[x].sum%=p;
     node[x].l=node[lson].l;
     node[x].r=node[rson].r;
}
inline void pushdown(ll x){
    ll lson=node[x].ls;
    ll rson=node[x].rs;
    node[lson].sum*=node[x].mul_lazy;
    node[rson].sum*=node[x].mul_lazy;
    node[lson].sum%=p;
    node[rson].sum%=p;
    node[lson].mul_lazy*=node[x].mul_lazy;
    node[rson].mul_lazy*=node[x].mul_lazy;
    node[lson].add_lazy*=node[x].mul_lazy;
    node[rson].add_lazy*=node[x].mul_lazy;
    node[lson].add_lazy%=p;
    node[rson].add_lazy%=p;
    node[lson].mul_lazy%=p;
    node[rson].mul_lazy%=p;
    node[x].mul_lazy=1;
    node[lson].sum+=node[x].add_lazy*(node[lson].r-node[lson].l+1);
        node[rson].sum+=node[x].add_lazy*(node[rson].r-node[rson].l+1);
        node[lson].sum%=p;
        node[rson].sum%=p;
        node[lson].add_lazy+=node[x].add_lazy;
        node[rson].add_lazy+=node[x].add_lazy;
        node[lson].add_lazy%=p;
        node[rson].add_lazy%=p; 
        node[x].add_lazy=0; 
}
inline void build(ll L,ll R,ll cur){
    if(L==R){
        node[cur].ls=node[cur].rs=-1;
        node[cur].l=node[cur].r=L;
        node[cur].sum=a[L];
        return;
    }
    node[cur].add_lazy=0;
    node[cur].mul_lazy=1;
    ll mid=(L+R)/2;
    node[cur].ls=++cnt;
    node[cur].rs=++cnt;
    build(L,mid,node[cur].ls);
    build(mid+1,R,node[cur].rs);
    pushup(cur);
}
inline void add_update(ll L,ll R,ll c,ll cur){
    if(L<=node[cur].l && node[cur].r<=R){
        node[cur].sum+=c*(node[cur].r-node[cur].l+1);
        node[cur].sum%=p;
        node[cur].add_lazy+=c;
        node[cur].add_lazy%=p;
        return;
    }
    pushdown(cur);
    ll mid=(node[cur].l+node[cur].r)/2;
    if(L<=mid)  add_update(L,R,c,node[cur].ls);
    if(mid<R)   add_update(L,R,c,node[cur].rs);
    pushup(cur);
}
inline void mul_update(ll L,ll R,ll c,ll cur){
    if(L<=node[cur].l && node[cur].r<=R){
        node[cur].sum*=c;
        node[cur].sum%=p;
        node[cur].add_lazy*=c;
        node[cur].mul_lazy*=c;
        node[cur].add_lazy%=p;
        node[cur].mul_lazy%=p;return; 
    }
    pushdown(cur);
    ll mid=(node[cur].l+node[cur].r)/2;
    if(L<=mid)  mul_update(L,R,c,node[cur].ls);
    if(mid<R)   mul_update(L,R,c,node[cur].rs);
    pushup(cur);
}
inline ll query(ll L,ll R,ll cur){
    if(L<=node[cur].l && node[cur].r<=R)
        return node[cur].sum;
    pushdown(cur);
    ll mid=(node[cur].l+node[cur].r)/2;
    ll tot=0;
    if(L<=mid)  tot+=query(L,R,node[cur].ls)%p;
    if(mid<R)   tot+=query(L,R,node[cur].rs)%p;
    return tot%p;    
}
int main(){
    scanf("%lld%lld%lld",&n,&m,&p);
    for(register int i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    rt=++cnt;
    build(1,n,rt);
    for(register int i=1;i<=m;i++){
        int a;
        scanf("%d",&a);
        if(a==1){
            ll x,y,z;
            scanf("%lld%lld%lld",&x,&y,&z);
            mul_update(x,y,z,rt);
        }
        else if(a==2){
            ll x,y,z;
            scanf("%lld%lld%lld",&x,&y,&z);
            add_update(x,y,z,rt);
        }
        else{
            ll x,y;
            scanf("%lld%lld",&x,&y);
            printf("%lld
",query(x,y,rt)%p);
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/sdfzsyq/p/9677172.html