隐藏页面特效

洛谷 P1383 高级打字机==codevs 3333 高级打字机

1|0P1383 高级打字机


    • 18通过
    • 118提交
  • 题目提供者yeszy
  • 标签倍增图论高级数据结构福建省历届夏令营
  • 难度省选/NOI-

提交该题 讨论 题解 记录

1|1最新讨论


  • 暂时没有讨论

1|2题目描述


早苗入手了最新的高级打字机。最新款自然有着与以往不同的功能,那就是它具备撤销功能,厉害吧。

请为这种高级打字机设计一个程序,支持如下3种操作:

1.T x:在文章末尾打下一个小写字母x。(type操作)

2.U x:撤销最后的x次修改操作。(Undo操作)

(注意Query操作并不算修改操作)

3.Q x:询问当前文章中第x个字母并输出。(Query操作)

文章一开始可以视为空串。

1|3输入输出格式


输入格式:

 

第1行:一个整数n,表示操作数量。

以下n行,每行一个命令。保证输入的命令合法。

 

输出格式:

 

每行输出一个字母,表示Query操作的答案。

 

1|4输入输出样例


输入样例#1:
7 T a T b T c Q 2 U 2 T c Q 2
输出样例#1:
b c

1|5说明


【数据范围】

对于40%的数据 n<=200;

对于100%的数据 n<=100000;保证Undo操作不会撤销Undo操作。

<高级挑战>

对于200%的数据 n<=100000;Undo操作可以撤销Undo操作。

<IOI挑战>

必须使用在线算法完成该题。

50分代码(栈模拟): 

#include<cstdio> using namespace std; #define N 51000 int top,T; char st[N]; int main(){ scanf("%d",&T); while(T--){ char c1[2],c2[2];int x; scanf("%s",c1); if(c1[0]=='T'){ scanf("%s",c2); st[++top]=c2[0]; } if(c1[0]=='U'){ scanf("%d",&x); top-=x; } if(c1[0]=='Q'){ scanf("%d",&x); printf("%c\n",st[x]); } } return 0; }

 

题解:

因为Undo操作只能撤销Type操作,所以Undo x 实际上就是删除文章末尾x个字母。用一个栈即可解决(每个字母最多进出一次)。

 

<高级挑战>    (考虑到部分选手水平较高,故设此附加题)

本题虽为2012年IOI的题目,但只要使用离线算法,就成为只需noip级别编程水平的题目了。

以下声明一些定义:(对于此类题目以及各种可持久化数据结构的离线解法的思考很有帮助)

版本:接受第1--i个修改操作(包含Type和Undo)后的状态称为版本i。版本0为初始状态。

版本链:一般的数据结构题目只有各种修改命令(比如本题的Type操作),那么所有版本就会呈链状排列。

这种情况下只需要设计一个合理的数据结构依次执行操作即可。

版本树:Undo x撤销最近的x次修改操作,实际上就是当前版本还原为x次操作前的版本,换句话说,版本i = 版本i-x-1。

 

如图所示,所有版本呈树状排列,版本0为根。

读入所有操作并建树,对这颗版本树按欧拉序求出所有版本。上图中就是按0->1->4...4->1->0->2->3->2->0的顺序遍历,同样使用栈就能计算出所有的版本,然后在对应的版本上解决询问即可。

    到此,就得到了时空复杂度均为O(n)的离线算法。

 

能解决这类题目的条件是:

1.允许使用离线算法,进而求出版本树,并允许把询问挂到树的节点上。

2.所有操作都是可逆的。只有所有操作都是可逆的,才能按欧拉序依次求出各版本。如本题的Type操作的逆操作就是弹出栈顶,Undo操作则根本不需要修改(Undo前后2个版本相同)。

相关题目:crisis 60% (2012 国家集训队hw2出题互测\卓亮)

 

<IOI挑战>

Trie+倍增法寻祖                                       O(nlogn)

各种可持久化数据结构:可持久化块状数组                O(nsqrtn)

                             可持久化跳表(与Trie解法相近) O(nlogn)

                          ......

 因超出noip范围不做更多展开。

AC代码(手写主席树):

 

#include<cstdio> using namespace std; const int R=1e5,N=(R+1)*20; int n,m,now,sz,root[R+1],ls[N],rs[N],len[N]; char s[N]; inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } void insert(int &k,int last,int l,int r,int pos,int c){ k=++sz; if(l==r){s[k]=c;return ;} ls[k]=ls[last]; rs[k]=rs[last]; int mid=l+r>>1; if(pos<=mid) insert(ls[k],ls[last],l,mid,pos,c); else insert(rs[k],rs[last],mid+1,r,pos,c); } void query(int &k,int last,int l,int r,int pos){ if(l==r){putchar(s[k]);putchar('\n');return ;} int mid=l+r>>1; if(pos<=mid) query(ls[k],ls[last],l,mid,pos); else query(rs[k],rs[last],mid+1,r,pos); } int main(){ n=read(); for(int i=1,x;i<=n;i++){ char op=0,ch=0; for(;op<'A'||op>'Z';op=getchar()); if(op=='T'){ for(;ch<'a'||ch>'z';ch=getchar()); now++; len[now]=len[now-1]+1; insert(root[now],root[now-1],1,R,len[now],ch); } else if(op=='U'){ x=read(); now++; root[now]=root[now-x-1]; len[now]=len[now-x-1]; } else x=read(),query(root[now],root[now-1],1,R,x); } return 0; }

 

 

 

AC代码(rope标程):

#include<cstdio> #include<iostream> #include<ext/rope> using namespace std; using namespace __gnu_cxx; const int maxn=1e5+10; rope<char> *his[maxn]; int n,m; inline char getC(){ for(register char ch=getchar();;ch=getchar()) if((ch>='A'&&ch<='Z')||(ch>='a'&&ch<='z')) return ch; } inline int getint(){ register int x=0,f=1; register char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int main(){ n=getint(); his[0]=new rope<char>(); for(int i=1;i<=n;i++){ char opt=getC(); if(opt=='T'){ m++; his[m]=new rope<char>(*his[m-1]);//就是这一句!它可以实现O(1)的拷贝历史版本,由于rope的底层是平衡树,copy时copy根节点就行了;用它就可以轻松实现可持久化数组 char x=getC(); his[m]->push_back(x); }else if(opt=='U'){ int x=getint(); m++; his[m]=new rope<char>(*his[m-x-1]); }else if(opt=='Q'){ int x=getint()-1; putchar(his[m]->at(x)); putchar('\n'); } } return 0; }

 


__EOF__

本文作者shenben
本文链接https://www.cnblogs.com/shenben/p/5837400.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   神犇(shenben)  阅读(1045)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
点击右上角即可分享
微信分享提示