题意:
长度为N的序列,初始时间戳为0,有M次操作。
C l r d:代表区间[l, r]的数加d,当前时间戳加1.
Q l r:代表输出当前时间戳内[l, r]的区间和.
H l r t:代表输出时间戳为t时[l, r]的区间和.
B t:代表把时间戳置为t.
题解:
先初始化一棵带lazy线段树,之后就是主席树的做法,查询就是线段树区间求和操作。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; const int maxn = 1e5+10; typedef long long ll; int n, m; int w[maxn]; int tot, tim; int root[maxn]; int l, r, t; char s[5]; struct node { int l, r, lazy; ll sum; }tre[maxn*40]; void build(int l, int r, int &x) { x = ++tot; tre[x].lazy = 0; if(l==r) { scanf("%lld", &tre[x].sum); return ; } int mid = l+r>>1; build(l, mid, tre[x].l); build(mid+1, r, tre[x].r); tre[x].sum = tre[tre[x].l].sum+tre[tre[x].r].sum; return ; } void update(int l, int r, int &x, int y, int ql, int qr, int val) { tre[++tot] = tre[y]; tre[tot].sum += 1ll*(qr-ql+1)*val; x = tot; if(l==ql&&qr==r) { tre[x].lazy += val; return ; } int mid = l+r>>1; if(qr<=mid) update(l, mid, tre[x].l, tre[y].l, ql, qr, val); else if(ql>mid) update(mid+1, r, tre[x].r, tre[y].r, ql, qr, val); else { update(l, mid, tre[x].l, tre[y].l, ql, mid, val); update(mid+1, r, tre[x].r, tre[y].r, mid+1, qr, val); } } ll query(int l, int r, int x, int ql, int qr) { if(ql==l&&qr==r) return tre[x].sum; int mid = l+r>>1; ll res = 1ll*(qr-ql+1)*tre[x].lazy; if(qr<=mid) res += query(l, mid, tre[x].l, ql, qr); else if(ql>mid) res += query(mid+1, r, tre[x].r, ql, qr); else res += query(l, mid, tre[x].l, ql, mid)+query(mid+1, r, tre[x].r, mid+1, qr); return res; } int main() { int f = 0; while(~scanf("%d%d", &n, &m)) { if(f) puts(""); f++; tim = tot = 0; build(1, n, root[0]); for(int i = 1; i <= m; i++) { scanf("%s", s); if(s[0]=='C') scanf("%d%d%d", &l, &r, &t), update(1, n, root[++tim], root[tim-1], l, r, t); if(s[0]=='Q') scanf("%d%d", &l, &r), printf("%lld ", query(1, n, root[tim], l, r)); if(s[0]=='H') scanf("%d%d%d", &l, &r, &t), printf("%lld ", query(1, n, root[t], l, r)); if(s[0]=='B') scanf("%d", &tim); } } }