由于UT并不会可持久化平衡树,因此他决定用一种奇怪的方法AC此题。
空间:线性。
缺点:离线。
首先,每个更新/查询都是基于一个历史版本的。
查询先不管,就看更新,相当于每个点有一个“父亲”,总的形成一个树结构(!
每个更新,相当于树上的一条边。
然后转回来处理查询,可以认为是在每个节点后面拖了一串询问。
那接着怎么做相信应该不难想到了吧?维护一棵平衡树然后dfs此更新树~
向下的时候,相当于直接操作。
回溯的时候,相当于是撤销了一条边上的操作。
看看操作,一加一删,正好支持撤销~
加变删,删变加(临时存一下被删掉的数)就好了。
然后,每进入到一个节点的时候,就把拖着的一串询问回答掉。
Over~
细节基本没有。
方便起见,使用了fhq-treap。
然后就是挫代码了(
#include <bits/stdc++.h>
#pragma GCC optimize("Ofast", 3, "inline")
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N = 1e6 + 9;
mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
struct node {
int val;
unsigned rnd;
int l, r;
int sz;
} tree[N];
int tot, root;
int newnode(int x) {
tree[++tot] = (node){x, rnd(), 0, 0, 1};
return tot;
}
void pushup(int x) { tree[x].sz = tree[tree[x].l].sz + tree[tree[x].r].sz + 1; }
void split(int now, int k, int& l, int& r) {
if (!now) {
l = r = 0;
return;
}
if (tree[tree[now].l].sz < k) {
l = now;
split(tree[now].r, k - tree[tree[now].l].sz - 1, tree[now].r, r);
} else {
r = now;
split(tree[now].l, k, l, tree[now].l);
}
pushup(now);
}
int merge(int x, int y) {
if (!x) return y;
if (!y) return x;
if (tree[x].rnd < tree[y].rnd) {
tree[x].r = merge(tree[x].r, y);
return pushup(x), x;
} else {
tree[y].l = merge(x, tree[y].l);
return pushup(y), y;
}
}
int kth(int k) {
int now = root;
while (1) {
int dl = tree[tree[now].l].sz;
if (k <= dl)
now = tree[now].l;
else if (k > dl + 1)
now = tree[now].r, k -= dl + 1;
else
return tree[now].val;
}
}
void insert_t_as_kth(int t, int k) {
int x, y;
split(root, k - 1, x, y);
root = merge(merge(x, newnode(t)), y);
}
void delete_kth(int k) {
int x, y, z;
split(root, k - 1, x, y);
split(y, 1, y, z);
root = merge(x, z);
}
void print(int now) {
if (!now) return;
print(tree[now].l);
printf("%d ", tree[now].val);
print(tree[now].r);
}
void print() {
print(root);
putchar('
');
}
const int __N__ = 3e5 + 9;
int fa[__N__], op[__N__], k[__N__], t[__N__];
int id[__N__];
vector<int> out[__N__];
vector<int> query[__N__];
int ans[N];
int cnt;
void dfs(int now) {
// printf("etring #%d
", now);
// print();
for (int q : query[now]) {
ans[q] = kth(k[q]);
}
for (int to : out[now]) {
// printf("fa:%d:", now), print();
if (op[to] == 1) {
insert_t_as_kth(t[to], k[to]);
dfs(to);
delete_kth(k[to]);
} else {
int x, y, z;
split(root, k[to] - 1, x, y);
split(y, 1, y, z);
int tmp = tree[y].val;
root = merge(x, z);
dfs(to);
insert_t_as_kth(tmp, k[to]);
}
}
}
int read() {
char c;
while (!isdigit(c = getchar()))
;
int x = c ^ 48;
while (isdigit(c = getchar())) x = x * 10 + (c ^ 48);
return x;
}
int main() {
memset(ans, -1, sizeof ans);
int m;
scanf("%d", &m);
for (int i = 1; i <= m; ++i) {
scanf("%d%d%d", op + i, fa + i, k + i);
// printf("fa[%d]=%d,id[%d]=%d;
", i, fa[i], fa[i], id[fa[i]]);
if (op[i] == 1) scanf("%d", t + i);
if (op[i] != 3)
id[++cnt] = i, out[id[fa[i]]].push_back(i);
else
query[id[fa[i]]].push_back(i);
}
dfs(0);
for (int i = 1; i <= m; ++i)
if (~ans[i]) printf("%d
", ans[i]);
return 0;
}