ABC283E 题解

前言

题目传送门!

更好的阅读体验?

很简单的一道题,强行在英语课的时候想到做法。

存储方式与其他题解稍有不同。本题解着重讲是怎么想到这个做法的。

思考过程

首先考虑暴力。用 \(n\) 个数组(或者 vector 等方式)记录不同版本,每次要保存或更改成版本,直接把 vector 粘贴过来当前列表即可,时间复杂度 \(O(q^2)\)

我们考虑是什么地方导致花销巨大:是存档操作。

我们发现,所有存档之间有一定联系。尝试用一个 \(pos_i\) 去记录第 \(i\) 个存档的位置。假设当前是在 \(cur\) 位置,备份直接 \(pos_i = cur\) 即可,然后直接做。

但是这样有一个明显的缺点:载入完后啥都做不了了啊!

正解

考虑下面的解决方法。

事实上,想到用树的方式存储,这题就做完了:

  • 对于 \(\texttt{ADD}\) 操作,只需要新建节点,并往当前的 \(cur\) 后面接儿子。然后跳过去。
  • 对于 \(\texttt{DEL}\) 操作,我们可以在 \(\texttt{ADD}\) 的时候记录一下,每一个节点的前一个节点是多少。直接跳 \(cur = fa_{cur}\)
  • 对于 \(\texttt{SAVE}\) 操作,直接 \(pos_i = cur\)
  • 对于 \(\texttt{LOAD}\) 操作,直接 \(cur = pos_i\)

每次输出 \(cur\) 的值即可。注意 \(pos_x\) 中的 \(x\) 可能会很大。可以离散化或者用更简单的 map 存储。

代码

#include <iostream>
#include <cstdio>
#include <vector>
#include <map>
using namespace std;
const int N = 5e5 + 5;
map <int, int> pos;
int fa[N], val[N];
vector <int> son[N]; //存储儿子 
int main()
{
	ios::sync_with_stdio(false);
	int T, cur = 0, idx = 0; //根节点是0 
	cin >> T;
	while (T--)
	{
		string op; int x;
		cin >> op;
		if (op != "DELETE") cin >> x;
		
		if (op == "ADD") son[cur].push_back(++idx), val[idx] = x,  fa[idx] = cur, cur = idx;
		else if (op == "DELETE") cur = fa[cur];
		else if (op == "SAVE") pos[x] = cur;
		else if (op == "LOAD") cur = pos[x];
		printf("%d ", val[cur] == 0 ? -1 : val[cur]); //注意空的时候输出 -1 而不是 0
	}
	return 0;
}

希望能帮助到大家!

posted @ 2023-02-13 18:20  liangbowen  阅读(28)  评论(0编辑  收藏  举报