P3372 【模板】线段树 1 区间修改 区间求和

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 100005
using namespace std;
typedef long long LL;
int n,m;
LL a[MAXN];
struct Node{
    int l,r;
    LL sm,ad;   
}tre[MAXN<<2];
void pushup(int rt)
{
    tre[rt].sm=tre[rt<<1].sm+tre[rt<<1|1].sm;
}
void pushdown(int rt)
{
    if(tre[rt].ad)
    {
        int tad=tre[rt].ad;
        tre[rt<<1].ad +=tad;//标记没有累加 
        tre[rt<<1|1].ad +=tad;//标记没有累加 
        tre[rt<<1].sm+=tad *(tre[rt<<1].r-tre[rt<<1].l+1);//(2)下放标记的同时,将该区间的sm值更新,以便于下次查询可以有sm的正确返回值 
        tre[rt<<1|1].sm+=tad *(tre[rt<<1|1].r-tre[rt<<1|1].l+1);
        tre[rt].ad =0;
    }
}
void build(int rt,int L,int R)
{
    tre[rt].l=L,tre[rt].r=R;
    if(L==R)
    {
        tre[rt].sm=a[L];return;
    }
    int mid=(L+R)>>1;
    build(rt<<1,L,mid);
    build(rt<<1|1,mid+1,R);
    pushup(rt);
}
void update(int rt,int L,int R,int v)//区间修改 
{
    if(L<=tre[rt].l && R>=tre[rt].r)
    {
        tre[rt].sm+=(tre[rt].r-tre[rt].l+1)*v;
        tre[rt].ad+=v;//标记没有累加 
        return ;
    }
    pushdown(rt);//(1)
    int mid=(tre[rt].l +tre[rt].r)>>1;
    if(L<=mid) update(rt<<1,L,R,v);
    if(R>mid) update(rt<<1|1,L,R,v);
    pushup(rt); 
}
LL query(int rt,int L,int R)
{
    if(L<=tre[rt].l && R>=tre[rt].r)
    {
        return tre[rt].sm ;
    }
    pushdown(rt);
    int mid=(tre[rt].l+tre[rt].r)>>1;
    LL ans=0;
    if(L<=mid)
        ans+=query(rt<<1,L,R);//少+ 
    if(R>mid)
        ans+=query(rt<<1|1,L,R);
    return ans;
}
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<=9;i++)cout<<tre[i].sm<<" "<<tre[i].l<<" "<<tre[i].r<<endl;
    int q,x,y;
    LL k;
    for(int i=1;i<=m;i++)
    {
        scanf("%d",&q);
        if(q==2)
        {
            scanf("%d%d",&x,&y);
            printf("%lld\n",query(1,x,y));
        }
        else{
            scanf("%d%d%lld",&x,&y,&k);
            update(1,x,y,k);
        }
    }
}
8 10
659 463 793 740 374 330 772 681 
1 5 8 39
2 5 8
1 3 6 3
1 5 8 90
1 1 5 21
2 3 8
1 3 8 17
1 4 7 52
2 2 6
1 2 7 41

2313
4281
3278

----
8 6
1 2 3 4 5 6 7 8
1 5 8 2
1 3 6 3
1 5 8 4
2 3 8
1 1 5 1
2 3 8

69
72
#include<bits/stdc++.h>
#define LL long long
using namespace std;

int n,m;
LL a[100005];
struct Tre{
  int l,r,cd;
  LL sm;
}tre[100005<<2];
void pushup(int rt)
{
    tre[rt].sm=tre[rt<<1].sm+tre[rt<<1|1].sm;
}
void build(int rt,int L,int R)
{
    tre[rt].l=L;
    tre[rt].r=R;
    if(L==R)
    {
        tre[rt].cd=0;
        tre[rt].sm=a[L];
        return;
    }
    int mid=(L+R)>>1;
    build(rt<<1,L,mid);
    build(rt<<1|1,mid+1,R);
    pushup(rt);
}
void pushdown(int rt)
{
    if(tre[rt].cd)
    {
        tre[rt<<1].cd+=tre[rt].cd;
        tre[rt<<1|1].cd+=tre[rt].cd;
        tre[rt<<1].sm+=(tre[rt<<1].r-tre[rt<<1].l+1)*tre[rt].cd;//这个地方1.少些了+,且写成了tre[rt<<1].cd 
        tre[rt<<1|1].sm+=(tre[rt<<1|1].r-tre[rt<<1|1].l+1)*tre[rt].cd;//这个地方少写了+,且写成了tre[rt<<1|1].cd 
        tre[rt].cd=0;
    }
}
void update(int rt,int L,int R,int v)
{
    if(L<=tre[rt].l && R>=tre[rt].r)
    {
        tre[rt].cd+=v;
        tre[rt].sm+=(tre[rt].r-tre[rt].l+1)*v;
        return; 
    }
    pushdown(rt);
    int mid=(tre[rt].l+tre[rt].r)>>1;
    if(L<=mid)
        update(rt<<1,L,R,v);
    if(R>mid)
        update(rt<<1|1,L,R,v);
    pushup(rt);
}
LL query(int rt,int L,int R)
{
    if(L<=tre[rt].l && R>=tre[rt].r)
    {
        return tre[rt].sm;
    }
    pushdown(rt);
    int mid=(tre[rt].l+tre[rt].r)>>1;
    LL sum=0;
    if(L<=mid)
        sum=query(rt<<1,L,R);
    if(R>mid)
        sum+=query(rt<<1|1,L,R);
    return sum;
}
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++)
    {
        int x,p,q;
        LL v;
        scanf("%d",&x);
        if(x==1)
        {
            scanf("%d%d%lld",&p,&q,&v); 
            update(1,p,q,v);
        }   
        else
        {
            scanf("%d%d",&p,&q);
            printf("%lld\n",query(1,p,q));
        }       
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值