线段树模板

Posted chilkings

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树模板相关的知识,希望对你有一定的参考价值。

https://oi-wiki.org/ds/seg/

poj3468

区间增减值,区间和。

线段树思想:利用二叉树将每一个区间所需要的值都记录下来。

lazy思想:延迟对叶子节点的修改,要用到的时候才真的去修改,lazy数组记录修改的值。

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1e6+10;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

ll a[maxn];
ll d[maxn<<2];
ll lazy[maxn<<2];

void PushDown(ll rt,ll l,ll r)   //下放懒惰标记 
{
    if(lazy[rt])
    {
    lazy[rt<<1] +=lazy[rt];    //左儿子懒惰标记加上当前父亲的懒惰值
    lazy[rt<<1|1]+=lazy[rt];   //右儿子懒惰标记加上当前父亲的懒惰值
    ll m=(l+r)>>1;
    d[rt<<1]+=lazy[rt]*(m-l+1); //左儿子的区间和加上父亲的懒惰标记值乘区间长度
    d[rt<<1|1]+=lazy[rt]*(r-m); //右儿子的区间和加上父亲的懒惰标记值乘区间长度
    lazy[rt] = 0;   //父亲懒惰值置0,懒惰标记下放完成
    }
}

void build(ll l,ll r,ll rt)
{
    //len[rt]=l-r+1;    可以用一个数组纪录每个节点对应的区间长度
    if(l==r)
    {
        d[rt]=a[l];return;
    }
    ll m=(l+r)>>1;
    build(lson);
    build(rson);
    d[rt]=d[rt<<1]+d[rt<<1|1];  //求和,可相应的改为max min等函数
}

void update(ll L,ll R,ll l,ll r,ll rt,ll val)//[L,R]目标区间 [l,r]当前区间
{
    if(L<=l && r<=R)   //如果当前区间在目标区间内
    {
        lazy[rt]+=val;  //打上懒惰标记
        d[rt]+=(r-l+1)*val; return;  //区间和加上区间长度乘val
    }
    PushDown(rt,l,r);      //下放懒惰标记 
    ll m=(l+r)>>1;
    if(m>=L)
    update(L,R,lson,val); //[l,L,m,r]   //说明与左儿子有交集
    if(R>m) 
    update(L,R,rson,val); //[l,m,R,r]   //说明与右儿子有交集
    d[rt]=d[lson]+d[rson];  //向上更新
}

ll query(ll L,ll R,ll l,ll r,ll rt)
{
    if(L<=l && r<=R)
    {
        return d[rt];
    }
    PushDown(rt,l,r);
    ll m=(l+r)>>1;
    ll res=0;
    if(L <= m) 
    res += query(L,R,lson);  
    if(R > m) 
    res += query(L,R,rson); 
    return res;
}

int main() 
{
    ll N,Q;
    scanf("%lld%lld",&N,&Q);
    for(int i=1;i<=N;i++)
    scanf("%lld",&a[i]);
    build(1,N,1);
    char ope[5];
    ll l,r,val;
    while(Q--)
    {   
        scanf("%s",ope);
        if(ope[0]=='Q')
        {
            scanf("%lld%lld",&l,&r);
            printf("%lld
",query(l,r,1,N,1));
        }
        else
        {
            scanf("%lld%lld%lld",&l,&r,&val);
            update(l,r,1,N,1,val);
        }
    }
    return 0;
}

以上是关于线段树模板的主要内容,如果未能解决你的问题,请参考以下文章

线段树模板整理

线段树模板总结

线段树模板

模板线段树-单点修改,区间查询

P3834 模板可持久化线段树 1(主席树)

模板 线段树(部分功能)