HDU_4348
用可持久化线段树就可以实现O(1)的back操作,同时如果想效率比较高的话,推荐用单点修改+区间查询的模式替代下传标记的区间修改+区间查询的模式来完成对区间和的查询。
至于如何不下传标记就能完成区间修改和区间求和可以参考ZKW的《统计的力量--线段树》的第59~60页。
#include<stdio.h> #include<string.h> #define MAXD 100010 typedef long long LL; int N, M, node, T[MAXD], np[MAXD]; LL A[MAXD]; struct SegTree { int ls, rs; LL d, nd; }st[2560000]; namespace ST { int build(int x = 1, int y = N) { int cur = ++ node, mid = x + y >> 1; st[cur].d = st[cur].nd = 0; if(x < y) st[cur].ls = build(x, mid), st[cur].rs = build(mid + 1, y); return cur; } int insert(int pre, int k, int d) { int t = ++ node, cur = t, x = 1, y = N; for(;;) { st[cur].d = st[pre].d + d, st[cur].nd = st[pre].nd + (LL)k * d; if(x == y) break; int mid = x + y >> 1; if(k <= mid) { st[cur].ls = ++ node, st[cur].rs = st[pre].rs; cur = node, pre = st[pre].ls, y = mid; } else { st[cur].rs = ++ node, st[cur].ls = st[pre].ls; cur = node, pre = st[pre].rs, x = mid + 1; } } return t; } } void init() { int i; A[0] = 0; for(i = 1; i <= N; i ++) scanf("%I64d", &A[i]), A[i] += A[i - 1]; node = 0, T[0] = ST::build(), np[0] = node; } LL query(int k, int t) { int cur = T[t], x = 1, y = N; LL d = 0, nd = 0; if(k == 0) return 0; for(;;) { if(x == y) { d += st[cur].d, nd += st[cur].nd; break; } int mid = x + y >> 1; if(k <= mid) cur = st[cur].ls, y = mid; else { d += st[st[cur].ls].d, nd += st[st[cur].ls].nd; cur = st[cur].rs, x = mid + 1; } } return A[k] + k * d - nd + d; } void solve() { int i, x, y, t, d, cur = 0; char op[5]; for(i = 0; i < M; i ++) { scanf("%s", op); if(op[0] == 'C') { scanf("%d%d%d", &x, &y, &d); ++ cur; T[cur] = ST::insert(T[cur - 1], x, d); if(y < N) T[cur] = ST::insert(T[cur], y + 1, -d); np[cur] = node; } else if(op[0] == 'Q') { scanf("%d%d", &x, &y); printf("%I64d\n", query(y, cur) - query(x - 1, cur)); } else if(op[0] == 'H') { scanf("%d%d%d", &x, &y, &t); printf("%I64d\n", query(y, t) - query(x - 1, t)); } else scanf("%d", &t), cur = t, node = np[t]; } } int main() { int t = 0; while(scanf("%d%d", &N, &M) == 2) { init(); if(t ++) printf("\n"); solve(); } return 0; }