线段树区间修改
这里给一个区间修改,求区间和的代码,也可以用到求区间最值,乘积等问题。
这个想法是sum[]和lazy[]同时修改。以前我写的是lazy[now]往下传给now << 1和now << 1 | 1的时候再修改sum[],这个写法的逻辑不是很好,推荐下面的这个思路。
1 #include<cstdio> 2 using namespace std; 3 typedef long long ll; 4 const int maxn = 1e5 + 5; 5 6 int l[maxn << 2], r[maxn << 2], lazy[maxn << 2]; 7 ll sum[maxn << 2]; 8 void build(int L, int R, int now) 9 { 10 l[now] = L; r[now] = R; 11 if(L == R) {scanf("%lld", &sum[now]); return;} 12 int mid = (L + R) >> 1; 13 build(L, mid, now << 1); 14 build(mid + 1, R, now << 1 | 1); 15 sum[now] = sum[now << 1] + sum[now << 1 | 1]; 16 } 17 void pushdown(int now) 18 { 19 if(lazy[now]) 20 { 21 lazy[now << 1] += lazy[now]; 22 lazy[now << 1 | 1] += lazy[now]; 23 sum[now << 1] += (r[now << 1] - l[now << 1] + 1) * lazy[now]; 24 sum[now << 1 | 1] += (r[now << 1 | 1] - l[now << 1 | 1] + 1) * lazy[now]; 25 lazy[now] = 0; 26 } 27 } 28 void update(int L, int R, int now, int d) 29 { 30 if(L == l[now] && R == r[now]) 31 { 32 sum[now] += (r[now] - l[now] + 1) * d; 33 lazy[now] += d; 34 return; 35 } 36 pushdown(now); 37 int mid = (l[now] + r[now]) >> 1; 38 if(R <= mid) update(L, R, now << 1, d); 39 else if(L > mid) update(L, R, now << 1 | 1, d); 40 else {update(L, mid, now << 1, d); update(mid + 1, R, now << 1 | 1, d);} 41 sum[now] = sum[now << 1] + sum[now << 1 | 1]; 42 } 43 ll query(int L, int R, int now) 44 { 45 if(L == l[now] && R == r[now]) return sum[now]; 46 pushdown(now); 47 int mid = (l[now] + r[now]) >> 1; 48 if(R <= mid) return query(L, R, now << 1); 49 else if(L > mid) return query(L, R, now << 1 | 1); 50 else return query(L, mid, now << 1) + query(mid + 1, R, now << 1 | 1); 51 } 52 53 int main() 54 { 55 int n, m; scanf("%d%d", &n, &m); 56 build(1, n, 1); 57 for(int i = 1; i <= m; ++i) 58 { 59 int d; scanf("%d", &d); 60 if(d == 1) 61 { 62 int a, b, c; scanf("%d%d%d", &a, &b, &c); 63 update(a, b, 1, c); 64 } 65 else 66 { 67 int a, b; scanf("%d%d", &a, &b); 68 printf("%lld\n", query(a, b, 1)); 69 } 70 } 71 }