题目大意:
一个计算机支持一下三中操作:
TT xx:在文章末尾打下一个小写字母xx。
UU xx:撤销最后的xx次修改操作。
QQ xx:询问当前文章中第xx个字母并输出。
InputInput
7
T a
T b
T c
Q 2
U 2
T c
Q 2
OutputOutput
b
c
思路:
IOI题目。。。
正解是主席树(当然啦什么TrieTrie+倍增法寻祖,可持久化跳表,可持久化块状数组无敌的东西都可以做)。
但是本蒟蒻是用滚动数组水过了这道题。
本题有三个阶段:
- 对于5050%的数据 n≤100000n≤100000;保证UU操作不会撤销UU操作.
- 对于100100%的数据 n≤100000n≤100000;UU操作可以撤销UU操作。
- IOIIOI挑战:必须使用在线算法完成该题。
阶段33就直接放弃了 毕竟我还不会主席树。
那么对于阶段11,我们只要模拟堆,就可以很简单地得到这部分分。
var
tail,n,i,j,x:longint;
c:array[1..100000] of char; //模拟堆
ch,orz:char;
begin
readln(n);
for i:=1 to n do
begin
read(ch,orz);
if ch='T' then //插入
begin
inc(tail);
readln(c[tail]); //放入堆顶
end;
if ch='Q' then //询问
begin
readln(x);
writeln(c[x]); //输出第i位
end;
if ch='U' then //删除
begin
readln(x);
dec(tail,x) //将最后x位输出
end;
end;
end.
对于阶段二,我们也要把它分为两部分。
我们可以开一个长度为100000100000的ansistringansistring数组ss,s[i]s[i]表示第ii种情况。再开一个sumsum,表示第几种情况。这样,当我们遇到UU操作时,把前面xx个操作还原,其实就是不做前xx个操作,直接赋值为s[sum-x-1]。这样可以得到90分。
var
sum,n,i,j,x:longint;
s:array[1..100000] of ansistring;
ch,orz:char;
begin
readln(n);
for i:=1 to n do
begin
read(ch,orz);
if ch='T' then
begin
readln(ch);
inc(sum);
s[sum]:=s[sum-1]+ch; //储存情况
end;
if ch='Q' then
begin
readln(x);
writeln(s[sum][x]); //输出现在的情况的第x位
end;
if ch='U' then
begin
readln(x);
inc(sum); //也算一种情况
s[sum]:=s[sum-1-x]; //直接取第sum-1-x位
end;
end;
end.
但是这样会MLE,ss数组开的太大了。所以我们要用滚动数组来优化。每次将sumsum%2000020000就可以了。
代码:
const
k=20000; //滚动数组,其他与90分代码一样。
var
sum,n,i,j,x:longint;
s:array[1..k] of ansistring;
ch,orz:char;
begin
readln(n);
for i:=1 to n do
begin
read(ch,orz);
if ch='T' then
begin
readln(ch);
inc(sum);
s[sum mod k]:=s[(sum-1)mod k]+ch;
end;
if ch='Q' then
begin
readln(x);
writeln(s[sum mod k][x]);
end;
if ch='U' then
begin
readln(x);
inc(sum);
s[sum mod k]:=s[(sum-1-x) mod k];
end;
end;
end.