[算法学习笔记] 可持久化栈

前置知识

可持久化,即对于每次更改,我们都期望记录它的历史信息。容易进行可持久化的数据结构通常满足 修改数据结构是,数据结构本身的拓扑序没有改变。,即形态没有改变。例如线段树,Trie 树,数组都可以容易地进行可持久化。

可持久化线段树前面已经讲过,见 算法学习笔记 线段树

在阅读本文前, 建议读者了解手写栈和链表操作。

概述

可持久化栈是一种支持 栈顶修改,回退历史版本,栈顶查询 的一种数据结构。由于手写栈依赖于数组,我们可以用可持久化数组解决问题。这样我们可以随机访问栈中元素。但很多情况下我们没有这种需求。省去随机访问需求后的可持久化栈可以做到单次修改时间复杂度 \(O(1)\),空间复杂度 \(O(n)\)。线性时间内就可以解决问题。

实现

原理非常简单,每次入栈我们存档,记录当前版本号所对应的栈顶元素。容易发现,多个版本串联起来就组成了我们的栈。类似于链表结构。

这里我们通过画图举例。

image

如图,我们有一个大小为 \(8\) 的栈,只不过这里将栈横过来了。依次入栈 \(1-8\)。类似于链表,我们记录每个节点的前驱。这样就把节点串起来了。如果想要删除,退回到前驱即可。如果想要回退到任意版本,我们记录每个版本对应的栈顶。回退即可。

接下来我们将讲解可持久化栈的例题。

例题

[ABC273E] Notebook

Description

有一个版本保存系统,共有 \(10^9\) 个版本,每个版本初始都为空列表,还需要维护一个列表(后称为“当前列表”)。
您需要实现如下四种操作:

  • ADD x:在当前列表的末尾添加 \(x\)
  • DELETE:如果当前列表非空,把当前列表的末尾最后一个数删除。否则,什么也不做。
  • SAVE x:把当前列表保存至第 \(x\) 版本(在此后完成的操作不会在第 \(x\) 版本中出现,而且保存后当前列表不清空)
  • LOAD x:把当前列表变成第 \(x\) 版本(直接赋值,而不是添加,而且保存后第 \(x\) 版本不清空)
    给定 \(q\) 次操作,每次操作是以上四种操作,求每次操作的当前列表的末尾最后一个数(若数组为空输出 \(-1\))。

可持久化栈的板子题。

对于 ADD 操作, 我们需要在添加同时,新开版本并记录当前版本的栈顶,同时将当前版本节点同上一个版本节点相连。这很简单,只需要开一个变量 last 记录上一个版本号即可。

对于 DELETE 操作,直接将当前所在版本回滚到它的前驱即可。

对于 SAVE 操作,保存版本即可。

对于 LOAD 操作,也就是回滚版本。由于我们先前已经记录了每个版本所对应的栈顶,直接回滚即可。

Code
#include <bits/stdc++.h>
using namespace std;
const int N = 5e5+5;
int n;
int q;
int idx = 0;
int fa[N],val[N];
map <int,int> pos;
int last = 0;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>q;
    for(int i=1;i<=q;i++)
    {
        string op;
        cin>>op;
        int x;
        if(op == "ADD")
        {
            cin>>x;
            idx ++;
            val[idx] = x;
            fa[idx] = last;
            last = idx; 
        }
        else if(op == "SAVE") 
        {
            cin>>x;
            pos[x] = last;
        }
        else if(op == "DELETE")
        {
            last = fa[last];
        }
        else
        {
            cin>>x;
            last = pos[x];
        }
        if(last) cout<<val[last]<<" ";
        else cout<<"-1"<<" "; 
    }
}

练习:Luogu P6182,和本题基本一致。都是可持久化栈的板子。

posted @ 2024-06-29 20:49  SXqwq  阅读(12)  评论(0编辑  收藏  举报