题解 P3919 【【模板】可持久化数组(可持久化线段树/平衡树)】

· · 题解

虽然这违反了模板的本意,但是本人认为这种做法也会对应于一类特别的题目。即考虑离线做法。

考虑到每一个版本都被一些版本所依赖,这种依赖关系可以被当做一棵树。在读入时建树,最后进行操作时就是将树从原点0处进行dfs。

对于询问直接存进答案数组,对于修改操作,进行修改后再dfs,结束后再撤回修改。

这种思路可以过掉部分题目,但前提是操作可逆,所以不能过掉诸如可持久化并查集的题目。

#include <cstdio>

using namespace std;

struct edge {
    int v;
    edge* next;
};

const int N = 1000010;

int n, m;
int a[N], ans[N], op[N], k[N], x[N];
edge* g[N];

void add_edge(int u, int v);
void dfs(int u);

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; ++i)
        scanf("%d", &a[i]);
    op[0] = 2;
    for (int i = 1; i <= m; ++i) {
        int v;
        scanf("%d%d%d", &v, &op[i], &k[i]);
        if (op[i] == 1)
            scanf("%d", &x[i]);
        add_edge(v, i);
    }
    dfs(0);
    for (int i = 1; i <= m; ++i)
        if (op[i] == 2)
            printf("%d\n", ans[i]);
    return 0;
}

void dfs(int u) {
    if (op[u] == 2) {
        ans[u] = a[k[u]];
        for (edge* p = g[u]; p; p = p->next)
            dfs(p->v);
    } else {
        int ori = a[k[u]];
        a[k[u]] = x[u];
        for (edge* p = g[u]; p; p = p->next)
            dfs(p->v);
        a[k[u]] = ori;
    }
}

void add_edge(int u, int v) {
    static edge pool[N];
    static edge* p = pool;
    p->v = v;
    p->next = g[u];
    g[u] = p;
    ++p;
}