【模板】线段树(区间加)

代码复杂度较高的数据结构……写过的最长的模板(你才写过几个模板啊)

这么个东西:
bd3eb13533fa828bcb5fe85ffe1f4134970a5a09.jpg

线段树是棵平衡二叉树qwq 所以我们可以用\(i*2\)\(i*2+1\)分别表示\(i\)的左儿子和右儿子

有点类似分块的思想 or 树状数组……???也是拆分拆分拆分求和求和求和

设置add的标记,省去一个个节点修改的很多时间

在修改&查询中不断维护父子关系

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
#define ll long long
#define MAXN 1000001
#define leftson cur<<1
#define rightson cur<<1|1 
#define mid ((l+r)>>1)
#define push_up ans[cur]=ans[leftson]+ans[rightson]
#define push_down lazyadd(leftson,l,mid,tag[cur]); lazyadd(rightson,mid+1,r,tag[cur]); tag[cur]=0
using namespace std;
ll ans[MAXN<<2],tag[MAXN<<2];
void build(ll cur,ll l,ll r)
{
    if (l==r)
    {
        scanf("%lld",&ans[cur]);
        return;
    }
    build(leftson,l,mid);
    build(rightson,mid+1,r);
    push_up;
}
inline void lazyadd(ll cur,ll l,ll r,ll delta)
{
    tag[cur]+=delta;
    ans[cur]+=delta*(r-l+1);
}
inline void change(ll adl,ll adr,ll cur,ll l,ll r,ll delta)
{
    if (adl<=l&&r<=adr)
    {
        ans[cur]+=delta*(r-l+1);
        tag[cur]+=delta;
        return;
    }
    push_down;
    if (adl<=mid) change(adl,adr,leftson,l,mid,delta);
    if (adr>mid)  change(adl,adr,rightson,mid+1,r,delta);
    push_up;
}
long long query(ll quel,ll quer,ll cur,ll l,ll r)
{
    if (quel<=l&&r<=quer)
    {
        return ans[cur];
    }
    push_down;
    ll answer=0;
    if (quel<=mid)
    {
        answer+=query(quel,quer,leftson,l,mid);
    }
    if (quer>mid)
    {
        answer+=query(quel,quer,rightson,mid+1,r);
    }
    return answer;
}
int main()
{
    ll n,m;
    scanf("%lld%lld",&n,&m);
    int cs;
    build(1,1,n);
    ll a,b,c;
    for (ll i=1;i<=m;i++)
    {
        scanf("%d",&cs);
        if (cs==1)
        {
            scanf("%lld%lld%lld",&a,&b,&c);
            change(a,b,1,1,n,c);
            continue;
        }
        scanf("%lld%lld",&a,&b);
        printf("%lld\n",query(a,b,1,1,n));
    }
    return 0;
}

转载于:https://www.cnblogs.com/Kan-kiz/p/10620906.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值