题目:codevs3333 高级打字机
【题目描述】
早苗入手了最新的高级打字机。最新款自然有着与以往不同的功能,那就是它具备撤销功能,厉害吧。请为这种高级打字机设计一个程序,支持如下3种操作:
1.T x:在文章末尾打下一个小写字母x。(type操作)
2.U x:撤销最后的x次修改操作。(Undo操作)(注意Query操作并不算修改操作)
3.Q x:询问当前文章中第x个字母并输出。(Query操作)
文章一开始可以视为空串。
【输入格式】
第1行:一个整数n,表示操作数量。
以下n行,每行一个命令。保证输入的命令合法。
【输出格式】
每行输出一个字母,表示Query操作的答案。
【样例输入】
7
T a
T b
T c
Q 2
U 2
T c
Q 2
【样例输出】
b
c
【数据范围】
对于40%的数据 n<=200;
对于100%的数据 n<=100000;保证Undo操作不会撤销Undo操作。
<高级挑战>
对于200%的数据 n<=100000;Undo操作可以撤销Undo操作。
<IOI挑战>
必须使用在线算法完成该题。
分析:
版本:接受第1--i个修改操作(包含Type和Undo)后的状态称为版本i。版本0为初始状态。
版本链:一般的数据结构题目只有各种修改命令(比如本题的Type操作),那么所有版本就会呈链状排列。
这种情况下只需要设计一个合理的数据结构依次执行操作即可。
版本树:Undo x撤销最近的x次修改操作,实际上就是当前版本还原为x次操作前的版本,换句话说,版本i = 版本i-x-1。
代码:
#include<cstdio>
#include<vector>
using namespace std;
const int maxn=100010;
int n,q,x,p,act;
int h[maxn],nxt[maxn],to[maxn],ans[maxn];
char ch,a[maxn],st[maxn];
vector <int> ques[maxn];
void build(int u,int v) {to[++p]=v;nxt[p]=h[u];h[u]=p;}
void dfs(int pos,int top)
{
for(int i=h[pos];i;i=nxt[i]) dfs(to[i],top);//undo
if(a[pos]) st[top]=a[pos],dfs(pos+1,top+1);//type
for(int i=0;i<ques[pos].size();i++){//query
int v=ques[pos][i];
ans[v]=st[ans[v]];
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%s",&ch);
switch (ch){
case 'T':scanf("%s",&a[act++]);break;
case 'U':{
scanf("%d",&x);act++;
build(act-x-1,act);
break;
}
case 'Q':{
scanf("%d",&x);
ques[act].push_back(++q);
ans[q]=x;
break;
}
}
}
dfs(0,1);
for(int i=1;i<=q;i++) printf("%c\n",ans[i]);
return 0;
}