正题
题目链接: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;
}
}
}
然后正题——撤销撤销
你知道吗?它的撤销可以撤销撤销!
它还可以撤销撤销撤销
还可以撤销撤销撤销撤销
……
好了,这道题支持离线算法所以我们就用离线算法。
离线算法我们要先构一颗树,我们发现如果是
操作的话可以直接和下一个版本相连然后加一个字母,如果是
操作的话那么版本
就等于版本
,所以我们连边
然后用欧拉序来求所有的版本,时间负责度
代码
#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]);//原序输出
}