1082 线段树练习 3 (线段树区间修改+区间求和)
题目描述 Description
给你N个数,有两种操作:
1:给区间[a,b]的所有数增加X
2:询问区间[a,b]的数的和。
输入描述 Input Description
第一行一个正整数n,接下来n行n个整数,
再接下来一个正整数Q,每行表示操作的个数,
如果第一个数是1,后接3个正整数,
表示在区间[a,b]内每个数增加X,如果是2,
表示操作2询问区间[a,b]的和是多少。
pascal选手请不要使用readln读入
输出描述 Output Description
对于每个询问输出一行一个答案
样例输入 Sample Input
3
1
2
3
2
1 2 3 2
2 2 3
样例输出 Sample Output
9
数据范围及提示 Data Size & Hint
数据范围
1<=n<=200000
1<=q<=200000
思路:
算是模板提吧,没什么难点,好久没写线段树了,写下熟悉下线段树区间操作,之前还有点不懂,后面自己独立写出来了感觉对这个的理解还是上升了。
实现代码:
#include<bits/stdc++.h> using namespace std; #define ll long long #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 const int M = 2e5 + 10; ll lazy[M<<2],sum[M<<2]; void pushup(int rt){ sum[rt] = sum[rt<<1] + sum[rt<<1|1]; } void pushdown(int rt,int m){ if(lazy[rt]){ lazy[rt<<1] += lazy[rt]; lazy[rt<<1|1] += lazy[rt]; sum[rt<<1] += lazy[rt]*(m-(m>>1)); sum[rt<<1|1] += lazy[rt]*(m>>1); lazy[rt] = 0; } } void build(int l,int r,int rt){ lazy[rt] = 0; if(l == r){ cin>>sum[rt]; return ; } int m = (l + r) >> 1; build(lson); build(rson); pushup(rt); } void update(int L,int R,int c,int l,int r,int rt){ if(L <= l&&R >= r){ lazy[rt] += c; sum[rt] += (r - l + 1)*c; return ; } pushdown(rt,r - l + 1); int m = (l + r) >> 1; if(L <= m) update(L,R,c,lson); if(R > m) update(L,R,c,rson); pushup(rt); } ll query(int L,int R,int l,int r,int rt){ if(L <= l&&R >= r){ return sum[rt]; } pushdown(rt,r - l + 1); int m = (l + r) >> 1; ll ret = 0; if(L <= m) ret += query(L,R,lson); if(R > m) ret += query(L,R,rson); return ret; } int main() { int n,q,x,l,r,c; cin>>n; build(1,n,1); cin>>q; while(q--){ cin>>x; if(x == 1){ cin>>l>>r>>c; update(l,r,c,1,n,1); } else{ cin>>l>>r; cout<<query(l,r,1,n,1)<<endl; } } return 0; }