标签:
咱家越来越懒了,连解释都懒得去写了,主要思想就是把一个区间当作一个线段,然后不断的递归二分最后成为各个点,关键在于lazy_tag,当你正在处理的区间完全在目标操作区间时就可以用lazy来处理,不再递归下去,思想是这样的,想要会的话呢,应该先去照着打两遍,边打边理解,然后就可以自己打啦
#include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <cmath> #define l(x) st[x].l #define r(x) st[x].r #define sum(x) st[x].sum #define lazy(x) st[x].lazy using namespace std; typedef long long ll; const int Size = 1e5 + 5; struct segment_tree{ int l,r; ll sum,lazy; }st[Size << 2]; int a[Size]; void build(int,int,int); void spread(int); void change(int,int,int,int); ll ask(int,int,int); int main(){ int n, q; scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); build(1, 1, n); scanf("%d",&q); for (int i = 0; i < q; i++){ int o,a, b, c; scanf("%d%d%d",&o,&a,&b); if (o==1){ scanf("%d", &c); change(1, a, b, c); } else cout << ask(1,a,b) << endl;//printf("%I64d\n", ask(1, a, b)); } return 0; } void build(int x,int l,int r){ l(x) = l,r(x) = r; if (l == r){ sum(x) = a[l]; return ; } int mid = l + r >> 1; build(x << 1,l,mid); build(x << 1| 1,mid + 1,r); sum(x) = sum(x << 1) + sum(x << 1 | 1); } void spread(int x){ if (lazy(x)){ sum(x << 1) += lazy(x) * (r(x << 1) - l(x << 1) + 1); sum(x << 1 | 1) += lazy(x) * (r(x << 1 | 1) - l(x << 1 | 1) + 1); lazy(x << 1) += lazy(x); lazy(x << 1 | 1) += lazy(x); lazy(x) = 0; } } void change(int x,int l,int r,int delta){ if (l <= l(x) && r >= r(x)){ sum(x) += delta * (r(x) - l(x) + 1); lazy(x) += delta; return ; } int mid = l(x) + r(x) >> 1; spread(x); if (l <= mid) change(x << 1,l,r,delta); if (r > mid) change(x << 1 | 1,l,r,delta); sum(x) = sum(x << 1) + sum(x << 1 | 1); return ; } ll ask(int x,int l,int r){ if (l <= l(x) && r >= r(x)) return sum(x); int mid = l(x) + r(x) >> 1; ll ans = 0; if (l <= mid) ans += ask(x << 1,l,r); if (r > mid) ans += ask(x << 1 | 1,l,r); return ans; }
OI模板——线段树(segment_tree)O(lg n)
标签:
原文地址:http://www.cnblogs.com/GENEVE/p/4803335.html