刷高代前的最后一道题,线段树的区间更新,这道题也让我管中窥豹般地观察到了线段树的一些深奥之处。
懒惰操作:我很懒,接收到更新操作后我先不着急更新,我先把自己的结点值更新了,为的是糊弄一部分查询操作,等到糊弄不过去不得不更新时我再更新,即要查询的区间比我维护的区间要更加地精确时。
这道题的话,注意下我注释的地方有溢出的可能性就行了
#include <iostream> #include <cstdio> using namespace std; typedef long long ll; const int N = 100100; struct Segtree{ int l, r; ll n, lazy; }segtree[N * 4]; void pushup(int k){ segtree[k]. n = segtree[k * 2]. n + segtree[k * 2 + 1]. n; } void pushdown(int k, int ln, int rn){ if(segtree[k]. lazy){ segtree[2 * k]. n += segtree[k]. lazy * ln; segtree[2 * k + 1]. n += segtree[k]. lazy * rn; segtree[2 * k]. lazy += segtree[k]. lazy; segtree[2 * k + 1]. lazy += segtree[k]. lazy; segtree[k]. lazy = 0; } } void build(int k, int l, int r){ segtree[k] = {l, r, 0, 0}; if(l == r){ scanf("%lld", &segtree[k]. n); return ; } int mid = (l + r) / 2; build(2 * k, l, mid); build(2 * k + 1, mid + 1, r); pushup(k); } void update(int k, int l, int r, int c){ if(segtree[k]. l == l && segtree[k]. r == r){ segtree[k]. n += ((ll)c) * (r - l + 1); // 注意这个地方,有溢出的可能 segtree[k]. lazy += c; return ; } int mid = (segtree[k]. l + segtree[k]. r) / 2; pushdown(k, mid - segtree[k]. l + 1, segtree[k]. r - mid); if(r <= mid) update(2 * k, l, r, c); else if(l > mid) update(2 * k + 1, l, r, c); else{ update(2 * k, l, mid, c); update(2 * k + 1, mid + 1, r, c); } pushup(k); } ll query(int k, int l, int r){ if(l == segtree[k]. l && segtree[k]. r == r) return segtree[k]. n; int mid = (segtree[k]. l + segtree[k]. r) / 2; pushdown(k, mid - segtree[k]. l + 1, segtree[k]. r - mid); if(r <= mid) return query(k * 2, l, r); else if(l > mid) return query(k * 2 + 1, l, r); else return query(k * 2, l, mid) + query(k * 2 + 1, mid + 1, r); } int main(){ int n, q; while(~ scanf("%d%d", &n, &q)){ build(1, 1, n); char c; int a, b, d; while(q --){ cin >> c; if(c == 'Q'){ scanf("%d%d", &a, &b); printf("%lld\n", query(1, a, b)); } if(c == 'C'){ scanf("%d%d%d", &a, &b, &d); update(1, a, b, d); } } } return 0; }
好了,这一阶段到此为止了,明天开始开启高等代数的旅程
不知道下次回来时,会到达何种境界。