P1383 高级打字机
Description
早苗入手了最新的高级打字机。最新款自然有着与以往不同的功能,那就是它具备撤销功能,厉害吧。
请为这种高级打字机设计一个程序,支持如下3种操作:
1.T x:在文章末尾打下一个小写字母x。(type操作)
2.U x:撤销最后的x次修改操作。(Undo操作)
(注意Query操作并不算修改操作)
3.Q x:询问当前文章中第x个字母并输出。(Query操作)
文章一开始可以视为空串。
Input
第1行:一个整数n,表示操作数量。
以下n行,每行一个命令。保证输入的命令合法。
Output
- 每行输出一个字母,表示Query操作的答案。
Sample Input
7 T a T b T c Q 2 U 2 T c Q 2
Sample Output
b c
Data Size
【数据范围】
对于40%的数据 n<=200;
对于100%的数据 n<=100000;保证Undo操作不会撤销Undo操作。
对于200%的数据 n<=100000;Undo操作可以撤销Undo操作。
必须使用在线算法完成该题。
题解:
- 主席树。
- 一开始无脑水了个vector上去,80pts。爆空间了。如果全是插入操作的话,空间复杂度近似于O(n^2)。后来就敲了一发主席树就过了。原因是每次插入操作都只是开了一条链的空间而已。总体空间复杂度大概是O(nlogn)
(大概 - 具体思路比较简单,每一个时间戳建一棵树,拿个数组记录每棵树插入到第几个位置然后就在原树上插入;撤销直接rt[i]=rt[i-x];查询查就是了。
#include <iostream> #include <cstdio> #define N 100005 using namespace std; struct T {int l,r,v;}t[N*32]; int n,dfn,dex; int cnt[N],rt[N]; int build(int l,int r) { int p=++dex,mid=l+r>>1; if(l==r) return p; t[p].l=build(l,mid); t[p].r=build(mid+1,r); return p; } int upd(int lat,int l,int r,int pos,int val) { int p=++dex,mid=l+r>>1; t[p]=t[lat]; if(l==r) {t[p].v=val;return p;} if(pos<=mid) t[p].l=upd(t[lat].l,l,mid,pos,val); else t[p].r=upd(t[lat].r,mid+1,r,pos,val); return p; } int ask(int p,int l,int r,int pos) { if(l==r) return t[p].v; int mid=l+r>>1; if(pos<=mid) return ask(t[p].l,l,mid,pos); return ask(t[p].r,mid+1,r,pos); } int main() { cin>>n; rt[0]=build(1,n); for(int i=1;i<=n;i++) { char c[3]; scanf("%s",c); if(c[0]=='T') { char x[3]; scanf("%s",x); dfn++,rt[dfn]=upd(rt[dfn-1],1,n,cnt[dfn-1]+1,x[0]-'a'+1); cnt[dfn]=cnt[dfn-1]+1; } else if(c[0]=='U') { int x; scanf("%d",&x); dfn++,rt[dfn]=rt[dfn-x-1]; cnt[dfn]=cnt[dfn-x-1]; } else if(c[0]=='Q') { int x; scanf("%d",&x); printf("%c\n",ask(rt[dfn],1,n,x)-1+'a'); } } return 0; }