线段树小记

Posted gk0328

tags:

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

普通线段树可以[先标记(tag)后更改]或[边推(tag)边更改]

打算从原来的[先标记(tag)后更改]改变为较为普及的[边推(tag)边更改]

这里放模板题代码

#include<cstdio>
#include<iostream>
#define N 100005
#define ll long long
using namespace std;
struct node
{
    int l,r;
    ll s,lz;
}t[N << 2];
ll a[N];
int n,m,opt,x,y;
ll z;
void merge(int p)
{
    t[p].s=t[p+p].s+t[p+p+1].s;
}
void build(int p,int l,int r)
{
    t[p].l=l,t[p].r=r;
    if (l==r)
    {
        t[p].s=a[l];
        t[p].lz=0;
        return;
    }
    int mid=(l+r) >> 1;
    build(p+p,l,mid);
    build(p+p+1,mid+1,r);
    merge(p);
}
void down_tag(int p,ll z)
{
    t[p].s+=z*(t[p].r-t[p].l+1);
    t[p].lz+=z;
}
void down(int p)
{
    down_tag(p+p,t[p].lz),down_tag(p+p+1,t[p].lz);
    t[p].lz=0;
}
void change(int p,int x,int y,ll z)
{
    if (t[p].l>y||t[p].r<x)
        return;
    if (t[p].l>=x&&t[p].r<=y)
    {
        t[p].s+=z*(t[p].r-t[p].l+1);
        t[p].lz+=z;
        return;
    }
    down(p);
    change(p+p,x,y,z);
    change(p+p+1,x,y,z);
    merge(p);
}
ll calc(int p,int x,int y)
{
    if (t[p].l>y||t[p].r<x)
        return 0;
    if (t[p].l>=x&&t[p].r<=y)
        return t[p].s;
    down(p);
    return calc(p+p,x,y)+calc(p+p+1,x,y);
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    build(1,1,n);
    for (int i=1;i<=m;i++)
    {
        scanf("%d",&opt);
        switch (opt)
        {
            case 1:
                scanf("%d%d%lld",&x,&y,&z);
                change(1,x,y,z);
                break;
            case 2:
                scanf("%d%d",&x,&y);
                printf("%lld
",calc(1,x,y));
                break;
        }
    }
}

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

线段树详解

2.23考试小记

平衡树学习小记

20230424小记

线段树-代码实现细节与技巧

线段树