jzoj3794,P1383-高级打字机【欧拉序,离线O(n)】

正题

题目链接: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;
        }
    }
}

然后正题——撤销撤销

你知道吗?它的撤销可以撤销撤销!
它还可以撤销撤销撤销
还可以撤销撤销撤销撤销
……

好了,这道题支持离线算法所以我们就用离线算法。
离线算法我们要先构一颗树,我们发现如果是 T 操作的话可以直接和下一个版本相连然后加一个字母,如果是 U     x 操作的话那么版本 x 就等于版本 x k 1 ,所以我们连边
这里写图片描述
然后用欧拉序来求所有的版本,时间负责度 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]);//原序输出
}

猜你喜欢

转载自blog.csdn.net/mr_wuyongcong/article/details/80991135