选拔赛 J题 哭泣的阿木木
一个模板题,差不多把线段树的板子操作都包括了
由于使用了过多的Q技能--绷带牵引,阿木木的绷带库存越来越少,有一天,阿木木去市场上采购绷带,市场上的绷带一共有n种,每一种绷带的价格为 aia_iai,由于受到金融危机的影响,绷带的价格出现了一些波动,记性很差的阿木木将绷带价格的波动记录了下来,一共有Q次操作,有时阿木木会记录下新的价格波动,有时阿木木会计算一段区间[L,R]的绷带的价格之和,但是阿木木的计算器一不小心丢了,所以请聪明的你们回答阿木木每次询问的结果。
已知第i种价格波动有三种形式:
- 将区间[L,R]绷带的价格增加k元
- 将区间[L,R]绷带的价格减少k元
- 将第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; }