线段树(模板)

刚学了线段树,趁现在理解比较清楚,写篇博客供以后翻阅,线段树有很多应用,如求区间总和,最大值,最小值等,总之求区间问题都可以想想线段树,这里以求和为例

定义全局变量

const int maxn=1e5+10;
struct node
{
    int L,R;//当前节点的左右区间
    long long big,sum,lazy;//数据类型根据题意改,sum为当前节点的总和
} tree[4*maxn];//开四倍于数据量的空间

回溯函数

void pushup(int p)
{
    tree[p].sum=tree[p*2].sum+tree[p*2+1].sum;
}

建树

void build(int l,int r,int p)
{
    tree[p].L=l,tree[p].R=r,tree[p].lazy=0;//给当前节点的左右区间和lazy初始值
    if(l==r)//叶子节点为递归边界
    {
        scanf("%lld",&tree[p].sum); //这里直接写入,减少使用一个存放数据的数组
        return ;//一定要return掉哦~
    }
    int mid=(l+r)/2;
    build(l,mid,2*p);//向左递归
    build(mid+1,r,p*2+1);//向右递归
    pushup(p);//回溯改变父亲节点的值
}

下压函数

//用于区间查询和区间修改,根据当前节点的lazy_tag改变儿子节点的数据
void pushdown(int p,int l,int r)//这里的l,r为左右孩子在待求区间里的个数,参照下面的查询函数理解
{
    if(tree[p].lazy)
    {
        tree[p*2].lazy+=tree[p].lazy;//改变儿子节点的lazy_tag
        tree[p*2+1].lazy+=tree[p].lazy;
        tree[p*2].sum+=tree[p].lazy*l;//根据当前节点lazy_tag改变儿子节点的值,这里可以体现lazy的延迟性
        tree[p*2+1].sum+=tree[p].lazy*r;
        tree[p].lazy=0;//当前节点的lazy变为0,完成下压操作
    }
}

区间查询

long long Quary(int a,int b,int p)//a,b为待求区间,p为当前节点的下标
{
    long long awn=0;//输出的待求区间的总和
    int l=tree[p].L;
    int r=tree[p].R;
    if(a<=l&&r<=b)//如果待求区间比当前节点包含的区间大,直接返回当前区间的值
    {
        return tree[p].sum;
    }
    int mid=(l+r)/2;
    pushdown(p,mid-l+1,r-mid);//2,3参数表示左右分别有几个含在区间内
    if(a<=mid)
        awn+=Quary(a,b,2*p);
    if(b>mid)//注意这里不能加等号,不然死循环导致越界
        awn+=Quary(a,b,2*p+1);
    return awn;
}

区间更新

void updata(int a,int b,int val,int p)
{
    int l=tree[p].L;
    int r=tree[p].R;
    if(a<=l&&r<=b)//如果待修改区间比当前节点的区间大,直接修改当前节点的值,同时修改lazy的值
    {
        tree[p].sum+=val*(r-l+1);
        tree[p].lazy+=val;
        return ;
    }
    int mid=(l+r)/2;
    pushdown(p,mid-l+1,r-mid);//lazy下压
    if(a<=mid)
        updata(a,b,val,2*p);
    if(b>mid)
        updata(a,b,val,2*p+1);
    pushup(p);
}

例题

vj C - A Simple Problem with Integers 模板题

AC代码:

#include <iostream>
#include <stdio.h>
using namespace std;

const int maxn=1e5+10;

struct node
{
    int L,R;
    long long big,sum,lazy;
} tree[4*maxn];
void pushup(int p)
{
    tree[p].sum=tree[p*2].sum+tree[p*2+1].sum;
}
void pushdown(int p,int l,int r)
{
    if(tree[p].lazy)
    {
        tree[p*2].lazy+=tree[p].lazy;
        tree[p*2+1].lazy+=tree[p].lazy;
        tree[p*2].sum+=tree[p].lazy*l;
        tree[p*2+1].sum+=tree[p].lazy*r;
        tree[p].lazy=0;
    }
}
void build(int l,int r,int p)
{
    tree[p].L=l,tree[p].R=r,tree[p].lazy=0;
    if(l==r)
    {
        scanf("%lld",&tree[p].sum);
        return ;
    }
    int mid=(l+r)/2;
    build(l,mid,2*p);
    build(mid+1,r,p*2+1);
    pushup(p);
}

long long Quary(int a,int b,int p)
{
    long long awn=0;
    int l=tree[p].L;
    int r=tree[p].R;
    if(a<=l&&r<=b)
    {
        return tree[p].sum;
    }
    int mid=(l+r)/2;
    pushdown(p,mid-l+1,r-mid);
    if(a<=mid)
        awn+=Quary(a,b,2*p);
    if(b>mid)
        awn+=Quary(a,b,2*p+1);
    return awn;
}

void updata(int a,int b,int val,int p)
{
    int l=tree[p].L;
    int r=tree[p].R;
    if(a<=l&&r<=b)
    {
        tree[p].sum+=val*(r-l+1);
        tree[p].lazy+=val;
        return ;
    }
    int mid=(l+r)/2;
    pushdown(p,mid-l+1,r-mid);
    if(a<=mid)
        updata(a,b,val,2*p);
    if(b>mid)
        updata(a,b,val,2*p+1);
    pushup(p);
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    build(1,n,1);
    int a,b,c;
    char ch;
    while(m--)
    {
        getchar();
        scanf("%c%d%d",&ch,&a,&b);
        if(ch=='Q')
            printf("%lld\n",Quary(a,b,1));
        else
        {
            scanf("%d",&c);
            updata(a,b,c,1);
        }
    }

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值