正题
题目链接:https://www.luogu.org/problemnew/show/P1383
大意
三个操作
T c:加入一个字符c
U x:撤销前x次操作(只包括T和U)
Q x:询问当前第x个字符
解题思路
对于50%的数据U不会撤销到U
所以我们可以直接暴力
#include<cstdio>
#include<iostream>
using namespace std;
int n,x,w;
char c,a[100001];
int main()
{scanf("%d\n",&n);for (int i=1;i<=n;i++){cin>>c;if (c=='U'){scanf("%d",&x);w-=x;}else if (c=='Q'){scanf("%d",&x);printf("%c\n",a[x]);}else{cin>>c;a[++w]=c;}}
}
然后正题——撤销撤销
你知道吗?它的撤销可以撤销撤销!
它还可以撤销撤销撤销
还可以撤销撤销撤销撤销
……
好了,这道题支持离线算法所以我们就用离线算法。
离线算法我们要先构一颗树,我们发现如果是TT操作的话可以直接和下一个版本相连然后加一个字母,如果是操作的话那么版本xx就等于版本,所以我们连边
然后用欧拉序来求所有的版本,时间负责度O(n)O(n)
代码
#include<cstdio>
#include<iostream>
#include<vector>
#define MN 100011
using namespace std;
vector<int> q[MN+1];//vertor库储存询问
struct node{int to,next,w;
}a[MN+1];
int p,x,k,tot,ls[MN+1],n,ans[MN+1];
char c,st[MN+1],s[MN+1];
void addl(int x,int y)//连边
{a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;
}
void dfs(int x,int sto)//欧拉序求答案
{for(int i=ls[x];i;i=a[i].next)dfs(a[i].to,sto);//自己搜索连接的版本if (s[x]) st[sto]=s[x],dfs(x+1,sto+1);//直接接到下一个版本for (int i=0;i<q[x].size();i++)ans[q[x][i]]=st[ans[q[x][i]]];//计算答案
}
int main()
{scanf("%d\n",&n);for (int i=1;i<=n;i++){cin>>c;if (c=='T'){cin>>s[k++];//标记操作}else if (c=='Q'){scanf("%d",&x);q[k].push_back(++p);//记录询问ans[p]=x;}else if (c=='U'){k++;scanf("%d",&x);addl(k-x-1,k);//连边}}dfs(0,1);//求答案for (int i=1;i<=p;i++)if (ans[i]) printf("%c\n",ans[i]);//原序输出
}