可持久化FHQ

后言

  • 为什么只需要在 split 的时候可持久化就可以了 而不用在合并的时候再做一次?

    • 因为,我们一次操作,都会先分裂,而我们只关心对一次操作之后的状态保留下来。所以合并的时候即使改变了状态也无所谓,因为我们并不关心中间的版本,而若是,分裂之后的状态也是有用的,那么我们合并也需要可持久化了。
  • 还有就是,由于我们涉及到了可持久化,操作,必不可少的需要在 down 的时候对儿子复制一遍。若是平衡树的话就可能导致没有儿子,但硬生生新加了一个编号为 0 的儿子,所以down的时候需要特判一下。

  • 参考实现

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <random>
using namespace std;
typedef long long ll;
mt19937 Rand;
const int N = 200200, M = N * 100;
struct node
{
    unsigned int k; int size, val; ll sum;
    int ls, rs, rev;
}t[M]; int idx;
void rev(int x) { if (x)t[x].rev ^= 1; }
void copynode(int& x) { idx++; t[idx] = t[x]; x = idx; }
int newnode(int v) { idx++; t[idx].k = Rand(); t[idx].sum = t[idx].val = v; t[idx].size = 1; return idx; }
void down(int x)
{
    if (t[x].rev)
    {
        if (t[x].ls)copynode(t[x].ls);
        if (t[x].rs)copynode(t[x].rs);
        swap(t[x].ls, t[x].rs);
        rev(t[x].ls); rev(t[x].rs); t[x].rev = 0;
    }
}
void up(int x)
{
    t[x].sum = t[t[x].ls].sum + t[t[x].rs].sum + t[x].val;
    t[x].size = t[t[x].ls].size + t[t[x].rs].size + 1;
}
void split(int x, int& l, int& r, int p)// [1,p) [p,n]
{
    if (!x) { l = r = 0; return; }
    copynode(x); down(x);
    if (t[t[x].ls].size + 1 < p)
    {
        l = x, split(t[x].rs, t[l].rs, r, p - t[t[x].ls].size - 1), up(l);
    }
    else
    {
        r = x, split(t[x].ls, l, t[r].ls, p), up(r);
    }
}
int merge(int x, int y)
{
    if (!x)return y; if (!y)return x;
    if (t[x].k < t[y].k)
    {
        down(x); t[x].rs = merge(t[x].rs, y); up(x); return x;
    }
    else
    {
        down(y); t[y].ls = merge(x, t[y].ls); up(y); return y;
    }
}
ll sum(int x, int p)
{
    if (p <= 0 || !x)return 0;
    if (t[x].size <= p)return t[x].sum;
    down(x); const int le = t[t[x].ls].size + 1;
    return (le <= p ? t[x].val : 0) + sum(t[x].ls, p) + sum(t[x].rs, p - le);
}
int rt[N];// son down copy
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr); cout.tie(nullptr);
    int n, m, v, opt; int a, b, c; ll last_ans = 0, L, R, p, x;
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> v >> opt; rt[i] = rt[v];
        if (opt == 1)// add p x
        {
            cin >> p >> x; p ^= last_ans; x ^= last_ans;
            split(rt[i], a, c, p + 1); b = newnode(x);
            rt[i] = merge(merge(a, b), c);
        }
        else if (opt == 2)// del p
        {
            cin >> p; p ^= last_ans;
            split(rt[i], a, b, p + 1);
            split(a, a, c, p);
            rt[i] = merge(a, b);
        }
        else if (opt == 3)// rev L R
        {
            cin >> L >> R; L ^= last_ans; R ^= last_ans;
            split(rt[i], b, c, R + 1);
            split(b, a, b, L);
            rev(b); rt[i] = merge(a, merge(b, c));
        }
        else // ask L R
        {
            cin >> L >> R; L ^= last_ans; R ^= last_ans;
            cout << (last_ans = sum(rt[i], R) - sum(rt[i], L - 1)) << '\n';
        }
    }
    return 0;
}
posted @ 2025-04-23 08:01  LUHCUH  阅读(11)  评论(0)    收藏  举报