题目
T x:在文章末尾打下一个小写字母x。(type操作)
U x:撤销最后的x次修改操作。(Undo操作)(注意Query操作并不算修改操作)
Q x:询问当前文章中第x个字母并输出。(Query操作)文章一开始可以视为空串。
分析
可持久化数据结构特别多,在此不多说,这种方法是Trie+倍增,bel表示版本,dep表示距离第一个版本的深度, f a [ i ] [ j ] fa[i][j] fa[i][j]表示第 i − 2 j + 1 i-2^j+1 i−2j+1的版本,倍增查询,当撤销时从第x个版本跳转到x-y-1个版本,输入字母就创建新的节点。时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)
代码
#include <cstdio>
#include <cctype>
#define gc getchar()
using namespace std;
int n,bel[100001],ne,nt,dep[100001],fa[100001][21]; char c[100001];
int in(){
int ans=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans;
}
int main(){
n=in();
while (n--){
scanf("\n"); char cho=gc; gc;
if (cho=='T'){
bel[++ne]=++nt;//创建新的版本
dep[nt]=dep[bel[ne-1]]+1;//深度
fa[nt][0]=bel[ne-1];//第i-2^0+1个版本是它本身
for (int i=0;fa[fa[nt][i]][i];i++)
fa[nt][i+1]=fa[fa[nt][i]][i];//倍增
c[nt]=gc;//加入字母
}
if (cho=='U') bel[++ne]=bel[ne-in()-1];//指向前面的版本
if (cho=='Q'){
int p=bel[ne];
for (int x=dep[p]-in(),i=0;x;x>>=1,i++)//倍增
if (x&1) p=fa[p][i];//当找到当前最早的祖先时继续找祖先
putchar(c[p]); putchar('\n');
}
}
return 0;
}
Another分析
可以用主席树,每次加入logn的点,时间复杂度O(nlogn)
代码
#include <cstdio>
#include <cctype>
#define gc getchar()
#define N 100001
using namespace std;
int n,len[N],rt[N],k,tot,x;
struct cmtree{
int lson[N*9],rson[N*9]; char val[N*9];
void add(int &t,int f,int l,int r,int pos,char c){
if (!t) t=++tot;//动态开点
if (l==r) val[t]=c;//叶子节点
else{
int mid=(l+r)>>1;
if (pos<=mid) rson[t]=rson[f],add(lson[t],lson[f],l,mid,pos,c);
else lson[t]=lson[f],add(rson[t],rson[f],mid+1,r,pos,c);
}
}
char query(int t,int l,int r,int pos){
if (l==r) return val[t];
else{
int mid=(l+r)>>1;
if (pos<=mid) return query(lson[t],l,mid,pos);
else return query(rson[t],mid+1,r,pos);
}
}
}tree;
int in(){
int ans=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans;
}
int main(){
n=in();
while (n--){
scanf("\n"); char cho=gc; gc;
if (cho=='T'){
len[++k]=len[k-1]+1; char c=gc;
tree.add(rt[k],rt[k-1],1,N,len[k],c);//建树
}
if (cho=='U') {x=in(); len[++k]=len[k-x-1]; rt[k]=rt[k-x-1];}//跳到前面的版本
if (cho=='Q') putchar(tree.query(rt[k],1,N,in())),putchar('\n');//输出答案
}
return 0;
}
}