POJ 3468 A Simple Problem with Integers (区间增减)

本文介绍了一种基于线段树的数据结构实现方法,重点在于如何进行区间增减操作及查询,通过递归方式更新线段树节点并利用懒惰传播优化大量更新操作。

线段树的区间增减,水题,帮助练手


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>

#define max(a,b) (a>b)?a:b
#define min(a,b) (a>b)?b:a
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
#define LL __int64
const int maxn = 500100;
using namespace std;
#define MAX INT_MAX
#define MIN INT_MIN
struct node
{
    int l,r;
    LL add,sum;  //add作为一个数的累加和,同时起标记的作用;
}T[300010];
int a[100005];   //add必须是__int64;
void putup(int id)
{
    T[id].sum=T[2*id].sum+T[2*id+1].sum;
}
void putdown(int id)
{
    if(T[id].add)
    {
        T[2*id].add+=T[id].add;
        T[2*id].sum += (T[2*id].r-T[2*id].l+1)*T[id].add;
        T[2*id+1].add+=T[id].add;
        T[2*id+1].sum += (T[2*id+1].r-T[2*id+1].l+1)*T[id].add;
        T[id].add=0;
    }
}
void creat(int l,int r,int id)
{
    T[id].l=l;
    T[id].r=r;
    T[id].add=0;
    if(l==r)
    {
        T[id].sum=a[r];
        return;
    }
    int mid=(l+r)>>1;
    creat(l,mid,2*id);
    creat(mid+1,r,2*id+1);
    putup(id);
}
void update(int from,int to,LL add,int id)
{
    if(from<=T[id].l&&to>=T[id].r)
    {
        T[id].add +=add;
        T[id].sum += (T[id].r-T[id].l+1)*add;
        return;
    }

    putdown(id);
    if(from<=T[2*id].r)
        update(from,to,add,2*id);
    if(to>=T[2*id+1].l)
        update(from,to,add,2*id+1);
    putup(id);
}
LL query(int from,int to,int id)
{
    if(from==T[id].l&&to==T[id].r)
        return T[id].sum;

    putdown(id);
    if(from>=T[2*id+1].l)
        return query(from,to,2*id+1);
    else if(to<=T[2*id].r)
        return query(from,to,2*id);
    else
    return query(from,T[2*id].r,2*id) + query(T[2*id+1].l,to,2*id+1);
}
int main()
{
    int n,m,A,B;
    LL add;
    char str[5];
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(int i=1; i<=n; i++)
            scanf("%d",&a[i]);
        creat(1,n,1);
        while(m--)
        {
            LL ans = 0;
            scanf("%s",str);
            if(str[0]=='C')
            {
                scanf("%d%d%I64d",&A,&B,&add);
                update(A,B,add,1);
            }
            else
            {
                scanf("%d%d",&A,&B);
                ans=query(A,B,1);
                printf("%I64d\n",ans);
            }
        }
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值