洛谷P1383 高级打字机(主席树)
本题重要的一个操作就是撤销之前的操作,并且可以撤销已经撤销的操作
所以我们可以使用主席树这种数据结构来维护,如果撤销,就是将当前版本指向指定位置的版本
这题其实没有建树的必要,但是我习惯建树,我们需要一个len数组和一个pos变量记录有多少个版本以及如果插入应该在哪个位置插入,这样只需线段树就能解决
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<string> #include<queue> using namespace std; typedef long long ll; const int N=1e5+10; int idx; int len[N]; int pos; int n; int root[N]; struct node{ int l,r; char num; }tr[N*32]; int build(int l,int r){ int q=++idx; if(l==r){ return q; } int mid=l+r>>1; tr[q].l=build(l,mid); tr[q].r=build(mid+1,r); return q; } int insert(int p,int l,int r,char c,int size){ int q=++idx; tr[q]=tr[p]; if(l==r){ tr[q].num=c; return q; } int mid=l+r>>1; if(size<=mid) tr[q].l=insert(tr[p].l,l,mid,c,size); else tr[q].r=insert(tr[p].r,mid+1,r,c,size); return q; } void query(int q,int l,int r,int size){ if(l==r){ cout<<tr[q].num<<endl; return ; } int mid=l+r>>1; if(size<=mid) query(tr[q].l,l,mid,size); else query(tr[q].r,mid+1,r,size); } int main(){ int i; cin>>n; root[0]=build(1,n); for(i=1;i<=n;i++){ string s; cin>>s; if(s=="T"){ char c; cin>>c; ++pos; len[pos]=len[pos-1]+1; root[pos]=insert(root[pos-1],1,n,c,len[pos-1]+1); } else if(s=="U"){ int x; cin>>x; ++pos; root[pos]=root[pos-x-1]; len[pos]=len[pos-x-1]; } else{ int x; cin>>x; query(root[pos],1,n,x); } } }
没有人不辛苦,只有人不喊疼