选拔赛 J题 哭泣的阿木木

一个模板题,差不多把线段树的板子操作都包括了

由于使用了过多的Q技能--绷带牵引,阿木木的绷带库存越来越少,有一天,阿木木去市场上采购绷带,市场上的绷带一共有n种,每一种绷带的价格为 aia_iai,由于受到金融危机的影响,绷带的价格出现了一些波动,记性很差的阿木木将绷带价格的波动记录了下来,一共有Q次操作,有时阿木木会记录下新的价格波动,有时阿木木会计算一段区间[L,R]的绷带的价格之和,但是阿木木的计算器一不小心丢了,所以请聪明的你们回答阿木木每次询问的结果。

已知第i种价格波动有三种形式:

  1. 将区间[L,R]绷带的价格增加k元
  2. 将区间[L,R]绷带的价格减少k元
  3. 将第i种绷带的价格变为 bbb

每次询问请输出区间[L,R] 内绷带的价格之和

Input

第一行输入N和Q(n∈[1,1000000],Q∈[1,1000000])代表N种绷带和Q次询问

接下来一行N个数ai,表示第i种绷带的价格,(ai∈[1,100000])

接下来Q次操作:

q1 L R k 表示将区间[L,R] 内的绷带价格增加k元 (k∈[1,10000],1<=L<R<=n)

q2 L R k 表示将区间[L,R]内的绷带价格减少k元 (k∈[1,10000],1<=L<R<=n)

q3 pos b表示将第pos种绷带的价格修改为b (pos∈[1,n],b∈[1,10000],1<=pos<=n)

q4 L R表示询问区间[L,R]内绷带的价格之和(1<=L<R<=n)

Output

输出每次询问的答案

(请注意过程中绷带的价格可能会变为负数)

Sample Input 1

9 9
10 8 5 7 5 2 6 1 10 
q3 7 1
q1 4 7 5
q2 4 6 7
q4 1 5
q2 1 3 7
q2 3 6 2
q4 4 9
q1 4 9 9
q4 1 8
#include <cstdio>
#include <algorithm>
#include <iostream>
using namespace std;
typedef long long ll;
typedef long long ll;
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
const int maxn = 1000007;
const int INF=0x7fffffff;
ll SUM[maxn<<2];
ll lazy[maxn<<2];
ll a[maxn];
void PushUP(ll rt)
{
    SUM[rt] = SUM[rt<<1] + SUM[rt<<1|1];
}
void putdown(ll rt,ll ln,ll rn) {
    if (lazy[rt]) {
        lazy[rt<<1] += lazy[rt];
        lazy[rt<<1|1] += lazy[rt];
        SUM[rt<<1] += lazy[rt] *ln;
        SUM[rt<<1|1] += lazy[rt] * rn;
        lazy[rt] = 0;
    }
}
void build(ll l,ll r,ll rt)     //建树
{
    if (l == r)
    {
        SUM[rt]=a[l];
        return ;
    }
    int m = (l + r) >> 1;
    build(lson);
    build(rson);
    PushUP(rt);
}
void update(int p,int v,int l,int r,int rt)    //单点替换,把p位置的值置为v
{
    if (l == r)
    {
        SUM[rt] = v;
        return ;
    }
   ll m = (l + r) >> 1;
    putdown(rt,m-l+1,r-m);
    if (p <= m) update(p,v,lson);
    else update(p, v, rson);
    PushUP(rt);
}
void update1(ll L,ll R,ll v,ll l,ll r,ll rt)    //将区间L~R的值增加v
{
    if (L <= l && r <= R)
    {
        lazy[rt] += v;
        SUM[rt] += v * (r - l + 1);
        return ;
    }
    ll m = (l + r) >> 1;
    putdown(rt, m-l+1,r-m);
    if (L <= m) update1(L, R, v, lson);
    if (m < R) update1(L, R, v, rson);
    PushUP(rt);
}
ll querySUM(ll L,ll R,ll l,ll r,ll rt)     //求L~R的和
{
    if (L <= l && r <= R)
    {
        return SUM[rt];
    }
    ll m = (l + r) >> 1;
    putdown(rt,m-l+1,r-m);
    ll ret = 0;
    if (L <= m) ret += querySUM(L, R, lson);
    if (R > m)  ret +=  querySUM(L, R, rson);
    return ret;
}
int main()
{
    int n, m;
    scanf("%d%d",&n,&m);
        for(ll i=1;i<=n;i++)
        {
             scanf("%lld", &a[i]);
        }
        build(1, n, 1);
        while (m --)
        {
            char op[4];
            ll a,b,c;
            scanf("%s",op);
            if(op[1]=='1')     //区间增加
            {
                scanf("%lld %lld %lld",&a,&b,&c);
                update1(a, b, c, 1, n, 1);
                //for(int i=1;i<=n;i++)
                 //   cout<<SUM[i]<<",";
               // cout<<endl;
            //cout<<"111"<<endl;
            }
            else if(op[1]=='2')     //区间减少
            {
                 scanf("%lld %lld %lld",&a,&b,&c);
                update1(a, b, -c, 1, n, 1);
               // for(int i=1;i<=n;i++)
                //cout<<SUM[i]<<",";
                //cout<<endl;
                //cout<<"222"<<endl;
            }
            else if(op[1]=='3') //单点替换
            {     scanf("%lld %lld",&a,&b);
                update(a, b, 1, n, 1);
                //for(int i=1;i<=n;i++)
                //cout<<SUM[i]<<",";
               // cout<<endl;
                //cout<<"3333"<<endl;
            }
            else if(op[1]=='4')   //区间求和
            {
                 scanf("%lld %lld",&a,&b);
                printf("%lld\n",querySUM(a, b, 1, n, 1));
                //for(int i=1;i<=n;i++)
                //cout<<SUM[i]<<",";
                //cout<<endl;
                //cout<<"***"<<endl;
            }
        }
    return 0;
}

 

posted @ 2019-03-25 20:45  悲离  阅读(305)  评论(0编辑  收藏  举报