【UOJ 53】线段树区间修改
【题目描述】:
如题,已知一个数列,你需要进行下面两种操作:
1.将某区间每一个数加上x
2.求出某区间每一个数的和
【输入描述】:
第一行包含两个整数N、M,分别表示该数列数字的个数和操作的总个数。
第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。
接下来M行每行包含3或4个整数,表示一个操作,具体如下:
操作1: 格式:1 x y k 含义:将区间[x,y]内每个数加上k
操作2: 格式:2 x y 含义:输出区间[x,y]内每个数的和
【输出描述】:
输出包含若干行整数,即为所有操作2的结果。
【样例输入】:
5 5
1 5 4 2 3
2 2 4
1 2 3 2
2 3 4
1 1 5 1
2 1 4
【样例输出】:
11
8
20
【时间限制、数据范围及描述】:
时间:1s 空间:128M
对于30%的数据:N<=8,M<=10
对于70%的数据:N<=1000,M<=10000
对于100%的数据:N<=100000,M<=100000
(数据保证在int64/long long数据范围内)
题解:emm线段树板子,不过找错找半天,哎
#include<cstdio> #include<iostream> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> typedef long long ll; using namespace std; const ll maxn=100005; ll n,m,x,y,jjj,z; long long Sum[maxn<<2],Add[maxn<<2]; ll A[maxn]; void PushUp(ll rt){Sum[rt]=Sum[rt*2]+Sum[rt*2+1];} void Build(ll l,ll r,ll rt){ if(l==r) { Sum[rt]=A[l]; return; } ll m=(l+r)>>1; Build(l,m,rt<<1); Build(m+1,r,rt<<1|1); PushUp(rt); } void PushDown(ll rt,ll ln,ll rn){ if(Add[rt]){ Add[rt<<1]+=Add[rt]; Add[rt<<1|1]+=Add[rt]; Sum[rt<<1]+=Add[rt]*ln; Sum[rt<<1|1]+=Add[rt]*rn; Add[rt]=0; } } long long Query(ll L,ll R,ll l,ll r,ll rt){ if(L <= l && r <= R) return Sum[rt]; ll m=(l+r)>>1; PushDown(rt,m-l+1,r-m); long long ANS=0; if(L <= m) ANS+=Query(L,R,l,m,rt<<1); if(R > m) ANS+=Query(L,R,m+1,r,rt<<1|1); return ANS; } void Update(ll L,ll R,ll C,ll l,ll r,ll rt){ if(L <= l && r <= R){ Sum[rt]+=C*(r-l+1); Add[rt]+=C; return ; } ll m=(l+r)>>1; PushDown(rt,m-l+1,r-m); if(L <= m) Update(L,R,C,l,m,rt<<1); if(R > m) Update(L,R,C,m+1,r,rt<<1|1); PushUp(rt); } int main(){ freopen("53.in","r",stdin); freopen("53.out","w",stdout); ll mt; scanf("%lld %lld",&n,&mt); for(ll i=1;i<=n;i++) scanf("%lld",&A[i]); Build(1,n,1); while(mt--){ scanf("%lld",&jjj); if(jjj==1){ scanf("%lld %lld %lld",&x,&y,&z); Update(x,y,z,1,n,1); } else{ scanf("%lld %lld",&x,&y); printf("%lld\n",Query(x,y,1,n,1)); } } return 0; }