高级打字机

考虑维护每个位置上的下标的值。
那么变为一个可持久化数组的玩法。
再考虑在串后面这个要求。
记录一下每颗线段树的有多少个字符就行了。
可持久化线段树一下就好了。
自己还是比较喜欢拿两颗树比对着复制的写法。

高级打字机
#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';
	}
}
原文地址:https://www.cnblogs.com/dixiao/p/14689021.html