【题解】【loj120】持久化序列

由于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('\n');
}
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\n", 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;\n", 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\n", ans[i]);
  return 0;
}
posted @ 2020-11-05 21:08  UnyieldingTrilobite  阅读(84)  评论(0编辑  收藏  举报