题意
给一个数组a,有n个数,m次操作。
1e5个数,1e5次查询
操作有四种,
C l r d:更新区间[l,r],值都加上d,并且时间前进1
Q l r:查询[l,r]的区间和
H l r t:查询t时刻的区间和
B t:回到t时刻(一定是历史时刻),且t时刻之后的操作都作废了。
题解
这道题的关键是怎么更新区间和。
本来线段树更新区间和要push down也就是把懒惰标记下移,但是这样,整个修改区间都需要新建线段树的节点,空间不够。
所以考虑在查询的时候传参数下去,也就是一路加上大区间的lazy值,这样就不用push down了。
typedef struct {
int l, r;
ll sum, lazy;//sum记录子区间的和、lazy表示所有子区间都要加的数
} node;
node v[N * 32];
需要注意的是lazy的处理,对于不同时间共用的节点我们不能改变其lazy值,因为会对之前的状态产生影响。故不能采用push_down操作。
记录lazy的值,从上往下找的时候累加,找到目标区间时加上即可。
作为主席树区间修改的板子题记录一下。
#include <iostream>
//#include "bits/stdc++.h"
#include "algorithm"
#include "cstring"
#include "vector"
#include "stack"
#include "queue"
#include "set"
#include "cmath"
//#include "unordered_map"
using namespace std;
#define ll long long
//#define int ll
#define double long double
#define inf 0x3f3f3f3f3f3f
#define MOD 10000000000007
#define N 100005
#define MAX 1e9
#define mid ((l+r)>>1)
typedef struct {
int l, r;
ll sum, lazy;//sum记录子区间的和、lazy表示所有子区间都要加的数
} node;
node v[N * 32];
int tot, n, m;
ll a[N];
int rt[N];
void push_up(int st, int l, int r) {
v[st].sum = v[v[st].l].sum + v[v[st].r].sum + (r - l + 1) * v[st].lazy;
}
void build(int &cur, int l, int r) {
v[cur = ++tot].sum = 0;
v[cur].lazy = 0;
if (l == r) {
v[cur].sum = a[l];
return;
}
build(v[cur].l, l, mid);
build(v[cur].r, mid + 1, r);
push_up(cur, l, r);
}
void modify(int &cur, int before, int l, int r, int L, int R, ll p) {
v[cur = ++tot] = v[before];
if (L <= l && r <= R) {
v[cur].lazy += p;
v[cur].sum += p * (r - l + 1);
return;
}
if (L <= mid) modify(v[cur].l, v[before].l, l, mid, L, R, p);
if (R > mid) modify(v[cur].r, v[before].r, mid + 1, r, L, R, p);
push_up(cur, l, r);
}
ll query(int cur, int l, int r, int L, int R, ll p) {
if (L <= l && r <= R) {
return v[cur].sum + p * (r - l + 1);
}
ll ans = 0;
if (L <= mid) ans += query(v[cur].l, l, mid, L, R, p + v[cur].lazy);
if (R > mid) ans += query(v[cur].r, mid + 1, r, L, R, p + v[cur].lazy);
return ans;
}
void solve() {
while (cin >> n >> m) {
tot=0;
int time = 0;
for (int i = 1; i <= n; i++) scanf("%lld", &a[i]);
build(rt[0], 1, n);
for (int i = 1; i <= m; i++) {
char c;
cin >> c;
if (c == 'C') {
ll d;
int l,r;
cin >> l >> r >> d;
modify(rt[time + 1], rt[time], 1, n, l, r, d);
time++;
}
if (c == 'Q') {
int l, r;
cin >> l >> r;
cout << query(rt[time], 1, n, l, r,0) << endl;
}
if (c == 'H') {
int l, r, t;
cin >> l >> r >> t;
cout << query(rt[t], 1, n, l, r,0) << endl;
}
if (c == 'B') {
int t;
cin >> t;
time = t;
}
}
}
}
signed main() {
int tt = 1;
//cin >> tt;
while (tt-- > 0) {
solve();
}
return 0;
}