SP11470 TTM - To the moon
想到的不是可持久化线段树与标记永久化,而是可持久化平衡树。
所以想用这个做法,首先你得会平衡树、可持久化平衡树、文艺平衡树与可持久化文艺平衡树,最好再练几道题。
做法与模板题一样的,不过把翻转标记换成了加法标记。
区间加法怎么打标记呢?
非常显然的有
void TagAdd(Vertex *p, const ll &c) {
p && (p->add += c, p->sum += c * p->siz, p->val += c);
}
即我们把该节点本身的值加上
那么之后只是裸的维护可持久化平衡树了。
建树用了
维护当前时间戳,可以用一个表示时间的变量来表示。
#include <cstdio>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 5;
struct Vertex {
ll val = 0, sum = 0, add = 0;
int siz = 0, cnt = 0;
unsigned rank = 0;
Vertex *son[2] = {};
Vertex(const ll &__val = 0) { val = sum = __val, son[add = 0] = son[siz = cnt = 1] = nullptr; }
Vertex* Copy() { return this ? &(*(new Vertex) = *this) : nullptr; }
} *rt[maxn];
int siz(Vertex *p) { return p ? p->siz : 0; }
ll sum(Vertex *p) { return p ? p->sum : 0; }
void Pushup(Vertex *p) { p && (p->siz = siz(*p->son) + siz(p->son[1]) + p->cnt, p->sum = sum(*p->son) + sum(p->son[1]) + p->val); }
void Maintain(Vertex *&p) { p && (p = p->Copy()); }
void TagAdd(Vertex *p, const ll &c) {
p && (p->add += c, p->sum += c * p->siz, p->val += c);
}
void Pushdown(Vertex *p) {
if (p && p->add) {
Maintain(*p->son), Maintain(p->son[1]);
p->add && (TagAdd(*p->son, p->add), TagAdd(p->son[1], p->add), p->add = 0);
}
}
void SplitRank(const int &k, Vertex *&u, Vertex *&v, Vertex *p) {
if (!p) return void(u = v = nullptr);
Pushdown(p);
if (k <= siz(*p->son)) v = p->Copy(), SplitRank(k, u, v->son[0], p->son[0]), Pushup(v);
else u = p->Copy(), SplitRank(k - siz(*p->son) - p->cnt, u->son[1], v, p->son[1]), Pushup(u);
}
void Merge(Vertex *u, Vertex *v, Vertex *&p) {
if (!u || !v) return void(p = u ? u : v);
Pushdown(u), Pushdown(v);
if (u->rank >= v->rank) p = v, Merge(u, p->son[0], p->son[0]);
else p = u, Merge(p->son[1], v, p->son[1]);
Pushup(p);
}
int n;
ll a[maxn];
void Build(const int &s = 1, const int &t = n, Vertex *&v = *rt, Vertex *u = nullptr) {
if (s > t) return;
int mid = s + ((t - s) >> 1);
v = new Vertex{a[mid]}, v->rank = u ? u->rank + 1 : 0;
if (s == t) return;
Build(s, mid - 1, v->son[0], v), Build(mid + 1, t, v->son[1], v);
Pushup(v);
}
void Add(const int &l, const int &r, const ll &x, Vertex *u, Vertex *&v) {
Vertex *a = nullptr, *b = nullptr, *c = nullptr;
SplitRank(l - 1, a, c, u), SplitRank(r - l + 1, b, c, c);
TagAdd(b, x);
Merge(b, c, c), Merge(a, c, v);
}
ll Get(const int &l, const int &r, Vertex *u) {
Vertex *a = nullptr, *b = nullptr, *c = nullptr;
SplitRank(l - 1, a, c, u), SplitRank(r - l + 1, b, c, c);
ll reply = b->sum;
return Merge(b, c, c), Merge(a, c, u), reply;
}
int m, now;
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i) scanf("%lld", a + i);
Build();
char c;
for (int l, r, x; m; --m) {
scanf(" %c%d", &c, &l);
if (c == 'B') now = l;
else {
scanf("%d", &r);
if (c == 'Q') printf("%lld", Get(l, r, rt[now])), putchar(10);
else {
scanf("%d", &x);
if (c == 'H') printf("%lld", Get(l, r, rt[x])), putchar(10);
else Add(l, r, x, rt[now], rt[now + 1]), ++now;
}
}
}
return 0;
}