高级打字机
考虑维护每个位置上的下标的值。
那么变为一个可持久化数组的玩法。
再考虑在串后面这个要求。
记录一下每颗线段树的有多少个字符就行了。
可持久化线段树一下就好了。
自己还是比较喜欢拿两颗树比对着复制的写法。
高级打字机
#include<iostream>
#include<cstdio>
#define ll long long
#define N 100005
struct P{int ls,rs,v,s;}e[N << 5];
ll head[N];//第几次操作的根节点。
ll cnt;//先建出初始的树。
#define mid ((l + r) >> 1)
inline int build(int l,int r){
int now = ++cnt;
e[now].s = 0,e[now].v = 0;
if(l == r)
return now;
e[now].ls = build(l,mid);
e[now].rs = build(mid + 1,r);
return now;
}
ll n;
char a,b;
inline void modity(ll q,ll p,ll l,ll r,ll to,ll k){
// std::cout<<q<<" "<<p<<" "<<l<<" "<<r<<" "<<to<<" "<<k<<std::endl;
e[q].s = e[p].s + 1;
if(l == r){
e[q].v = k;
return ;
}
if(mid < to){
e[q].ls = e[p].ls;
e[q].rs = ++cnt;
modity(e[q].rs,e[p].rs,mid + 1,r,to,k);
}else{
e[q].rs = e[p].rs;
e[q].ls = ++cnt;
modity(e[q].ls,e[p].ls,l,mid,to,k);
}
}
inline int q(ll now,ll l,ll r,ll to){
// std::cout<<now<<" "<<l<<" "<<r<<" "<<to<<std::endl;
if(l == r)
return e[now].v;
if(mid < to)
return q(e[now].rs,mid + 1,r,to);
else
return q(e[now].ls,l,mid,to);
}
ll sum;
int main(){
scanf("%lld",&n);
head[0] = build(1,N);
ll p = head[0];//原树
for(int i = 1;i <= n;++i){
while(a != 'T' && a != 'Q'&& a != 'U')
a = getchar();
// std::cout<<i<<" "<<p<<std::endl;
if(a == 'T'){
while(b < 'a' || b > 'z')
b = getchar();
ll k = b - 'a' + 1;
head[++sum] = ++cnt;
modity(head[sum],p,1,N,e[p].s + 1,k);
p = head[sum];
}
if(a == 'Q'){
ll k;
scanf("%lld",&k);
std::cout<<(char)('a' + q(p,1,N,k) - 1)<<std::endl;
}
if(a == 'U'){
ll k;
scanf("%lld",&k);
p = head[sum - k];
// std::cout<<p<<std::endl;
head[++sum] = p;
}
a = 'z';
b = 'T';
}
}