bzoj1014

时间:2023-03-08 21:06:24

动态询问LCP,所以我们不好用后缀数组
考虑使用维护序列问题的splay+hash求LCP
这里mark一下,hash求LCP常用mo=9875321
自然溢出的话交上去莫名其妙WA了
这里树上某节点hash值代表的是这棵子树所代表的序列hash值
求LCP时,只要二分答案然后提取区间判断hash是否相同即可,实践证明错误率很小
这里注意要尽量少取模运算,否则会TLE

 const mo=;
var son:array[-..,..] of longint;
count,fa,hash,a:array[-..] of longint;
d:array[..] of longint;
m,n,root,i,x,y,s:longint;
ch:char; procedure update(x:longint);
var l,r:longint;
begin
l:=son[x,];
r:=son[x,];
count[x]:=count[l]+count[r]+;
hash[x]:=hash[l]+a[x]*d[count[l]]+int64(hash[r])*int64(d[count[l]+]) mod mo; //计算hash
hash[x]:=hash[x] mod mo;
end; function find(k:longint):longint;
var p:longint;
begin
p:=root;
while true do
begin
if count[son[p,]]+=k then exit(p);
if count[son[p,]]+>k then p:=son[p,]
else begin
k:=k-count[son[p,]]-;
p:=son[p,];
end;
end;
end; procedure rotate(x,w:longint);
var y:longint;
begin
y:=fa[x];
if fa[y]<>- then
begin
if son[fa[y],]=y then son[fa[y],]:=x
else son[fa[y],]:=x;
end
else root:=x;
fa[x]:=fa[y];
son[y,-w]:=son[x,w];
if son[x,w]<>- then fa[son[x,w]]:=y;
son[x,w]:=y;
fa[y]:=x;
update(y);
end; procedure splay(x,f:longint);
var y:longint;
begin
while fa[x]<>f do
begin
y:=fa[x];
if fa[y]=f then
begin
if son[y,]=x then rotate(x,)
else rotate(x,);
end
else begin
if son[fa[y],]=y then
begin
if son[y,]=x then rotate(y,) else rotate(x,);
rotate(x,);
end
else begin
if son[y,]=x then rotate(x,) else rotate(y,);
rotate(x,);
end;
end;
end;
update(x); //这是学LCT的时候发现的一个优化,每次rotate只要update父节点即可,这样一下子快了2s多
end; procedure insert(x,y:longint);
begin
x:=find(x+);
splay(x,-);
inc(n);
a[n]:=y;
son[n,]:=son[x,];
fa[son[x,]]:=n;
son[x,]:=n;
fa[n]:=x;
update(n);
update(x);
end; procedure change(x,y:longint);
begin
x:=find(x+);
splay(x,-);
a[x]:=y;
update(x);
end; function build(l,r:longint):longint;
var m:longint;
begin
m:=(l+r) shr ;
build:=m;
if l<=m- then
begin
son[m,]:=build(l,m-);
fa[son[m,]]:=m;
end;
if m+<=r then
begin
son[m,]:=build(m+,r);
fa[son[m,]]:=m;
end;
update(m);
end; function check(x,l,r:longint):longint;
var y:longint;
begin
y:=find(l+r+);
splay(x,-);
splay(y,x);
exit(hash[son[y,]]);
end; function ask(x,y:longint):longint;
var l,r,m,wx,wy:longint;
begin
l:=;
r:=n-y;
if n-x<r then r:=n-x;
ask:=;
wx:=find(x);
wy:=find(y);
while l<=r do
begin
m:=(l+r) shr ;
if check(wx,x,m)=check(wy,y,m) then
begin
l:=m+;
ask:=m;
end
else r:=m-;
end;
end; begin
fillchar(son,sizeof(son),);
fillchar(fa,sizeof(fa),);
read(ch);
while (ch>='a') and (ch<='z') do
begin
inc(n);
a[n]:=ord(ch)-;
read(ch);
end;
readln(m);
d[]:=;
for i:= to do
d[i]:=d[i-]* mod mo;
root:=build(,n+);
inc(n);
for i:= to m do
begin
read(ch);
if ch='Q' then
begin
readln(x,y);
writeln(ask(x,y));
end
else if ch='I' then
begin
read(x);
read(ch);
readln(ch);
y:=ord(ch)-;
insert(x,y);
end
else if ch='R' then
begin
read(x);
read(ch);
readln(ch);
y:=ord(ch)-;
change(x,y);
end;
end;
end.