可持久化数据结构维护可持久化数组
可持久化数据结构维护可持久化数组
首先我们要知道,"UNDO"操作,也就是直接跳回前面的操作(历史操作),然后跳回的地方到现在的地方这一个区间的操作都不用管。(这就是高级挑战的思路)
(可持久化是指一种可以访问历史版本的数据结构)然后我们就可以知道,询问历史,又是数组,也就是可持久化数组。可持久化数组的维护很简单,我们可以开一个\(O(N^2)\)的矩阵,然后进行操作。但是这样子空间会爆炸,怎么办?所以可持久化数组又可以用可持久化线段树来维护,虽然有很多空间浪费了,不过空间也还是\(O(N\ log\ N)\)(因为每一个数带来的空间是\(log\ n\)的)。
所以就这样子咯,如果还不会可持久化线段树(主席树)的可以去做洛谷的模板。
// luogu-judger-enable-o2
var
n,cnt,hao,tot:longint;
len,lson,rson,root:array[0..2000035] of longint;
value:array[0..2000035] of char;
s:string;
HuHa:char;
procedure build(var rt:longint; fa,l,r,po:longint); //插入一个数
var
mid:longint;
begin
if (rt=0) then
begin
inc(tot);
rt:=tot; //动态开点
end;
if l=r then //到了叶子节点
begin
value[rt]:=HuHa; //赋值
exit; //退出
end;
mid:=(l+r) div 2;
if (po<=mid) then //po就是key位置,我现在在最后(一个栈)插入一个数,po就是最后的位置
begin
rson[rt]:=rson[fa]; //垃圾回收
build(lson[rt],lson[fa],l,mid,po); //左走
end;
if (po>=mid+1) then //同上
begin
lson[rt]:=lson[fa];
build(rson[rt],rson[fa],mid+1,r,po);
end;
end;
function Query(rt,l,r,po:longint):char; //查询
var
mid:longint;
begin
if l=r then //到了指定位置(不一定是po)
exit(value[rt]);
mid:=(l+r) div 2; // 线段树常识
if (po<=mid) then
exit(Query(lson[rt],l,mid,po));
if (po>=mid+1) then
exit(Query(rson[rt],mid+1,r,po));
end;
begin
readln(n);
while n>0 do
begin
readln(s);
if s[1]='T' then
begin
HuHa:=s[3]; //直接截取
inc(cnt);
len[cnt]:=len[cnt-1]+1; //新的位置
Build(root[cnt],root[cnt-1],1,100007,len[cnt]); //插入
end;
if s[1]='U' then
begin
delete(s,1,2);
val(s,hao);
inc(cnt);
len[cnt]:=len[cnt-hao-1]; //位置往前推
root[cnt]:=root[cnt-hao-1]; //Root往前推(没一个数都有一个log链,当然有一个根)
end;
if s[1]='Q' then
begin
delete(s,1,2);
val(s,hao);
writeln(Query(root[cnt],1,100007,hao)); // 查询,我们不知道最长的长度是多少,所以就100007就可以了,log不会超过20
end;
dec(n);
end;
end.
完结撒花!✿✿ヽ(゚▽゚)ノ✿