【模板】可持久化文艺平衡树
题目大意
要你维护插入,删除,区间翻转,区间求和。
但要求可持续化,即每次操作在一个历史版本上进行,且会产生一个新的历史版本
思路
看到题目都是可持续化平衡树了。
直接上 splay,这题要多搞一个 down。
down 交换左右儿子之前要复制左右儿子。
然后其他的就跟 可持久化平衡树 是差不多的了。
代码
#include<queue>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define ll long long
using namespace std;
int n, rt[200001], bb, op, x, y, tot;
int ls[200001 << 7], rs[200001 << 7], yj[200001 << 7], sz[200001 << 7];
bool turn[200001 << 7];
ll sum[200001 << 7], lastans, val[200001 << 7];
int newpoint(ll num) {
int re = ++tot;
ls[re] = rs[re] = turn[re] = 0;
val[re] = num;
sum[re] = num;
yj[re] = rand();
sz[re] = 1;
return re;
}
int copypoint(int pl) {
int re = ++tot;
ls[re] = ls[pl];
rs[re] = rs[pl];
val[re] = val[pl];
sum[re] = sum[pl];
yj[re] = yj[pl];
turn[re] = turn[pl];
sz[re] = sz[pl];
return re;
}
void up(int now) {
sz[now] = sz[ls[now]] + sz[rs[now]] + 1;
sum[now] = sum[ls[now]] + sum[rs[now]] + val[now];
}
void down(int now) {
if (turn[now]) {
if (ls[now]) ls[now] = copypoint(ls[now]);
if (rs[now]) rs[now] = copypoint(rs[now]);
swap(ls[now], rs[now]);
if (ls[now]) turn[ls[now]] ^= 1;
if (rs[now]) turn[rs[now]] ^= 1;
turn[now] ^= 1;
}
}
pair <int, int> split_rnk(int now, int rnk) {
if (!now) return make_pair(0, 0);
if (!rnk) return make_pair(0, copypoint(now));
down(now);
pair <int, int> re;
if (rnk <= sz[ls[now]]) {
int noww = copypoint(now);
re = split_rnk(ls[noww], rnk);
ls[noww] = re.second;
up(noww);
re.second = noww;
}
else {
int noww = copypoint(now);
re = split_rnk(rs[noww], rnk - sz[ls[now]] - 1);
rs[noww] = re.first;
up(noww);
re.first = noww;
}
return re;
}
int merge(int x, int y) {
if (x) down(x);
if (y) down(y);
if (!x) return y;
if (!y) return x;
if (yj[x] < yj[y]) {
int xx = copypoint(x);
rs[xx] = merge(rs[xx], y);
up(xx);
return xx;
}
else {
int yy = copypoint(y);
ls[yy] = merge(x, ls[yy]);
up(yy);
return yy;
}
}
void insert(int bb, int pl, int num) {
pair <int, int> x = split_rnk(rt[bb], pl);
int y = newpoint(num);
rt[bb] = merge(x.first, merge(y, x.second));
}
void delete_(int bb, int pl) {
pair <int, int> x = split_rnk(rt[bb], pl - 1);
pair <int, int> y = split_rnk(x.second, 1);
rt[bb] = merge(x.first, y.second);
}
void turn_(int bb, int l, int r) {
pair <int, int> x = split_rnk(rt[bb], l - 1);
pair <int, int> y = split_rnk(x.second, r - l + 1);
turn[y.first] ^= 1;
rt[bb] = merge(merge(x.first, y.first), y.second);
}
ll get_sum(int bb, int l, int r) {
pair <int, int> x = split_rnk(rt[bb], l - 1);
pair <int, int> y = split_rnk(x.second, r - l + 1);
return sum[y.first];
}
int main() {
srand(19491001);
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d %d", &bb, &op);
rt[i] = rt[bb];
if (op == 1) {
scanf("%d %d", &x, &y);
x ^= lastans; y ^= lastans;
insert(i, x, y);
continue;
}
if (op == 2) {
scanf("%d", &x);
x ^= lastans;
delete_(i, x);
continue;
}
if (op == 3) {
scanf("%d %d", &x, &y);
x ^= lastans;
y ^= lastans;
turn_(i, x, y);
continue;
}
if (op == 4) {
scanf("%d %d", &x, &y);
x ^= lastans;
y ^= lastans;
lastans = get_sum(i, x, y);
printf("%lld\n", lastans);
}
}
return 0;
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现