Atcoder Beginner Contest 273E - Notebook 解题报告
1 题目链接
2 题目大意
题目:笔记本
题目大意:
有一个版本保存系统,共有
1
0
9
10^9
109 个版本,每个版本初始都为空列表,还需要维护一个列表(后称为“当前列表”)。
您需要实现如下四种操作:
ADD x
:在当前列表的末尾添加 x x x。DELETE
:如果当前列表非空,把当前列表的末尾最后一个数删除。否则,什么也不做。SAVE x
:把当前列表保存至第 x x x 版本(在此后完成的操作不会在第 x x x 版本中出现,而且保存后当前列表不清空)LOAD x
:把当前列表变成第 x x x 版本(直接赋值,而不是添加,而且保存后第 x x x 版本不清空)
给定 q q q 次操作,每次操作是以上四种操作,求每次操作后的当前列表的末尾最后一个数(若数组为空输出 − 1 -1 −1)。
3 解法分析
首先考虑纯模拟。
显然一眼假,但是可以借鉴纯模拟的思路。
不难发现所有的版本都是由一个最远古的版本经过不断地修改得来的。
对比树,发现可以用树来模拟整个过程。
考虑用 c u r cur cur 与 i d x idx idx 表示当前的最后一个点, f a [ c u r ] fa[cur] fa[cur] 表示上一个, v a l [ c u r ] val[cur] val[cur] 表示该点对应的数值, e [ i ] e[i] e[i] 用来存这棵树,且当有向图存,最后用 m p mp mp 来处理不同树枝上的跳转。
按照建树的过程模拟一下就结束了。
注意可以先将所有的 v a l [ i ] val[i] val[i] 赋初值 − 1 -1 −1 ,这样就不用特判可以直接输出了。
4 AC Code
#include <bits/stdc++.h>
#define rep(i, a, b) for (int (i) = (a); (i) <= (b); ++(i))
#define fep(i, a, b) for (int (i) = (a); (i) < (b); ++(i))
#define N 500007
using namespace std;
int x;
string ty;
int cur, idx;
int fa[N], val[N];
vector <int> e[N];
map <int, int> mp;
void solve() {
cin >> ty;
if (ty != "DELETE")
scanf("%d", &x);
if (ty == "ADD") {
e[cur].push_back(++idx);
val[idx] = x;
fa[idx] = cur;
cur = idx;
}
else if (ty == "DELETE")
cur = fa[cur];
else if (ty == "SAVE")
mp[x] = cur;
else if (ty == "LOAD")
cur = mp[x];
printf("%d ", val[cur]);
return ;
}
int T;
int main() {
fep(i, 0, N)
val[i] = -1;
scanf("%d", &T);
while (T--)
solve();
return 0;
}