C - A Simple Problem with Integers POJ - 3468

https://cn.vjudge.net/contest/280153#problem/C

#include <iostream>
#include<cstdio>
#define ll long long
using namespace std;
const ll maxn = 1e5+1000;

struct node
{
    ll l;
    ll r;
    ll sum;
    ll lazy;
    node()
    {
        lazy = 0;
        sum = 0;
    }
}Segtr[6*maxn];

ll num[maxn];
void pushdown(ll n);
void input(int N)
{
    for(int i = 1;i <= N;i++)
    {
        cin>>num[i];
    }
}
/*************建树函数****************.*/
void build(ll l, ll r, ll rt)//
{
    Segtr[rt].l = l;
    Segtr[rt].r = r;
    ll mid = (l+r)/2;
    Segtr[rt].lazy = 0;
    Segtr[rt].sum = 0;
    if(l == r)
    {
        Segtr[rt].sum = num[l];
        return;
    }

    build(l, mid, 2*rt+1);
    build(mid+1, r, 2*rt+2);
    Segtr[rt].sum = Segtr[2*rt+1].sum+Segtr[2*rt+2].sum;
}
/**************更新函数**********************/
void update(ll l, ll r, ll rt,ll add)// 要修改 l,r区间边界 , rt树节点编号, add修改的值
{
    ll L = Segtr[rt].l;
    ll R = Segtr[rt].r;


    if(Segtr[rt].lazy&&L!=R) pushdown(rt); //之前lazy 标记 就将他压给 子区间


    if(L == l && R == r)// 如果 正好与 该区间吻合  , 修改, 并标记, 返回
    {
        Segtr[rt].sum+=(R-L+1)*add;
        Segtr[rt].lazy+=add;//懒人标记
        return;
    }

    ll mid = (L+R)/2;// (L+R)/2;

    if(r <= mid)// 要修改的区间 在 mid  左面
    {
        update(l, r, rt*2+1, add);
    }
    else if(l > mid)
    {
        update(l, r, rt*2+2, add);
    }
    else
    {
        update(l , mid, rt*2+1, add);
        update(mid+1, r, rt*2+2, add);
    }

    Segtr[rt].sum = Segtr[2*rt+1].sum+Segtr[2*rt+2].sum; // 父亲等于 修改后的两个子区间的值之和


}
/**************标记 下压 函数*****************/
void pushdown(ll rt)
{
    /**修改 左区间的 值*/
    Segtr[2*rt+1].sum += Segtr[rt].lazy*(Segtr[2*rt+1].r - Segtr[2*rt+1].l +1);
    Segtr[2*rt+1].lazy += Segtr[rt].lazy; //给左子区间打上标记
    /****修改 右区间 值****/
    Segtr[2*rt+2].sum+=Segtr[rt].lazy*(Segtr[2*rt+2].r - Segtr[2*rt+2].l+1);
    Segtr[2*rt+2].lazy += Segtr[rt].lazy;//给右子区间打上标记

    Segtr[rt].sum = Segtr[2*rt+1].sum + Segtr[2*rt+2].sum;// 这里 可以删去
    Segtr[rt].lazy = 0; // 取消父区间的标记


}
/********************询问函数**********************/
ll query(ll l, ll r, ll rt)
{
    ll res = 0;
    ll L = Segtr[rt].l;
    ll R = Segtr[rt].r;
    ll mid = (L+R)/2;
    if(Segtr[rt].lazy&& L!= R) pushdown(rt);// L == R 表示 该节点是叶子节点 就不需要 继续往下压了
    if(L == l && R == r)
    {
        return Segtr[rt].sum;
    }



     if(r <= mid)
    {

        res = query(l, r, 2*rt+1);
    }
    else if(l > mid)
    {
        res = query(l, r, 2*rt+2);
    }
    else
    {
        res+=query(l, mid, 2*rt+1);
        res+=query(mid+1, r, 2*rt+2);
    }

    return res;

}

int main(void)
{

    ll N, Q;
    scanf("%lld %lld", &N, &Q);

    input(N);
    build(1, N, 0);


    while(Q--)
    {
        char op[2];
        ll l ,r, add;

        scanf("%s %lld %lld", op, &l, &r);

        if(op[0] == 'C')
        {
            scanf("%lld", &add);
            update(l, r, 0, add);//

        }
        else
        {
            ll res = query(l, r, 0);
            printf("%lld\n", res);
        }

    }




    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值