POJ 3468 A Simple Problem with Integers(线段树 区间修改)

本题数组要开大点,而且要用long long
代码:

#include<iostream>
#include<stdio.h>
using namespace std;
typedef long long ll;
const ll maxn=100010;
ll lazy[4*maxn],tr[4*maxn],r[4*maxn];
void pushdown(ll po,ll ljs,ll rjs)//向下推lazy标记
{
    if(lazy[po])
    {
   		 //通过本区间lazy标记值改变下面区间lazy标记值
        lazy[2*po]+=lazy[po];
        lazy[2*po+1]+=lazy[po];
        tr[2*po]+=lazy[po]*ljs;//ljs左边数量
        tr[2*po+1]+=lazy[po]*rjs;//rjs右边数量
        lazy[po]=0;
    }
}
void line_change(ll a,ll b,ll c,ll le,ll ri,ll po)//区间修改
{
    if(a<=le&&b>=ri)//当前区间完全在要进行修改的区间内
    {
        tr[po]+=c*(ri-le+1);
        lazy[po]+=c;//修改本区间lazy标记值
        ll av=(le+ri)/2;
    }
    else//只在进行修改的区间属于当前区间时进行
    {
        ll av=(le+ri)/2;
        pushdown(po,av-le+1,ri-av);
        if(a<=av)
            line_change(a,b,c,le,av,2*po);
        if(b>av)
            line_change(a,b,c,av+1,ri,2*po+1);
        tr[po]=tr[po*2]+tr[po*2+1];//自下而上对结点更新
    }
}
void build(ll le,ll ri,ll po)//创建树
{
    if(le==ri)
        tr[po]=r[ri];//每个叶结点
    else
    {
        build(le,(le+ri)/2,2*po);//左边
        build((le+ri)/2+1,ri,2*po+1);//右边
        tr[po]=tr[po*2]+tr[po*2+1];//自下而上对结点更新
    }
}
ll query(ll a,ll b,ll le,ll ri,ll po)//区间查询
{
    if(a<=le&&b>=ri)
        return tr[po];
    ll av=(le+ri)/2;
    pushdown(po,av-le+1,ri-av);//下推标记,不然返回的可能是修改之前的值
    ll sum=0;
    //递归返回累计答案
    if(a<=av)
        sum+=query(a,b,le,av,po*2);
    if(b>av)
        sum+=query(a,b,av+1,ri,po*2+1);
    return sum;
}
int main()
{
    ll n,m;
    while(scanf("%lld%lld",&n,&m)!=EOF)
    {
        for(ll i=1;i<=n;++i)
        {
            scanf("%lld",&r[i]);
        }
        build(1,n,1);
        for(ll i=0;i<m;++i)
        {
            char c[2];
            scanf("%s",c);
            if(c[0]=='Q')
            {
                ll a,b;
                scanf("%lld%lld",&a,&b);
                printf("%lld\n",query(a,b,1,n,1));
            }
            if(c[0]=='C')
            {
                ll a,b,c;
                scanf("%lld%lld%lld",&a,&b,&c);
                line_change(a,b,c,1,n,1);
            }
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值