基本线段树模板

#include <bits/stdc++.h>
#define endl '\n'
#define INF 0x3f3f3f3f
#define ll long long
using namespace std;
const int N=1000010;
struct node
{
    ll sum,lazy;
    int l,r;
}tr[N<<2];//线段树结点要开数据量的四倍
ll input[N];
int n,m;
void pushup(int u)//向上更新
{
    tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;
}
void change(int u,ll lazy)
{
    tr[u].sum+=(tr[u].r-tr[u].l+1)*lazy;//利用父节点的懒标记更新当前结点的sum
    tr[u].lazy+=lazy;//更新当前节点的懒标记
}
void pushdown(int u)//向下更新
{
    if(tr[u].lazy)
    {
        change(u<<1,tr[u].lazy);//利用懒标记更新左右儿子
        change(u<<1|1,tr[u].lazy);
        tr[u].lazy=0;//已用懒标记更新左右二次,懒标记清零
    }
}
void build(int u,int l,int r)//建立线段树
{
    tr[u].l=l,tr[u].r=r;
    if(l==r)//当左右端点相同说明为叶子节点
    {
        tr[u].sum=input[l];
        return ;
    }
    int mid=(r+l)>>1;
    build(u<<1,l,mid);
    build(u<<1|1,mid+1,r);
    pushup(u);
}
void add(int u,int pos,ll k)//单点修改
{
    if(tr[u].l==tr[u].r)//如果左右端点相同说明找到了要查询的点
    {
        tr[u].sum+=k;
        return ;
    }
    int mid=tr[u].l+tr[u].r>>1;
    if(mid>=pos)add(u<<1,pos,k);//单点修改只需要修改一个点所以用if else
    else add(u<<1|1,pos,k);
    pushup(u);//返回更新祖宗节点
}
ll query(int u,int l,int r)//区间询问
{
    if(tr[u].l>=l&&tr[u].r<=r)return tr[u].sum;
    pushdown(u);//询问时需要用懒标记实时更新所查询到的结点
    ll res=0;
    int mid=tr[u].l+tr[u].r>>1;//当前区间中点
    if(l<=mid)res+=query(u<<1,l,r);//如果当前结点的中点在所要查询区间左端点的右边
    //则说明左儿子包含一部分查询区间
    if(r>mid)res+=query(u<<1|1,l,r);//右儿子结点同理
    return res;
}
void modify(int u,int l,int r,ll k)//区间修改
{
    if(tr[u].l>=l&&tr[u].r<=r)
    {
        change(u,k);
        return ;
    }
    pushdown(u);
    int mid=tr[u].l+tr[u].r>>1;
    if(l<=mid)modify(u<<1,l,r,k);
    if(r>mid)modify(u<<1|1,l,r,k);
    pushup(u);
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        cin>>input[i];
    }
    build(1,1,n);
    for(int i=0;i<m;i++)
    {
        int type;
        cin>>type;
        if(type==1)
        {
            int l,r;
            ll k;
            cin>>l>>r>>k;
            modify(1,l,r,k);
        }
        else
        {
            int l,r;
            cin>>l>>r;
            cout<<query(1,l,r)<<endl;
        }
    }
    return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值