传送门
http://www.lydsy.com/JudgeOnline/problem.php?id=3879
题目大意
给定一个字符串
每次询问这个字符串得一些后缀两两之间的
lcp
之和
题解
建立反串的SAM得到后缀树
求点间的LCP转化为LCA
每次建立虚树就好了
const
maxn=500005;
type
data=record
fa,len,key:longint;
tranc:array[0..26]of longint;
end;
var
x:array[0..3*maxn]of data;
w:array[0..6*maxn,1..2]of longint;
fa,t,pos,y,dep,z,clear:array[0..3*maxn]of longint;
size:array[0..3*maxn]of longint;
st:array[0..3*maxn,0..20]of longint;
i,j,k:longint;
n,m,tot,tail,len,a,b,top,tt:longint;
stt:ansistring;
sum:int64;
procedure sort(l,r:longint);
var i,j,a,b:longint;
begin
i:=l; j:=r; a:=pos[z[(l+r)div 2]];
repeat
while pos[z[i]]<a do inc(i);
while a<pos[z[j]] do dec(j);
if not (i>j) then
begin b:=z[i]; z[i]:=z[j]; z[j]:=b; inc(i); dec(j); end;
until i>j;
if l<j then sort(l,j);
if i<r then sort(i,r);
end;
procedure sort1(l,r:longint);
var i,j,a,b:longint;
begin
i:=l; j:=r; a:=pos[clear[(l+r)div 2]];
repeat
while pos[clear[i]]<a do inc(i);
while a<pos[clear[j]] do dec(j);
if not (i>j) then
begin b:=clear[i]; clear[i]:=clear[j]; clear[j]:=b; inc(i); dec(j); end;
until i>j;
if l<j then sort(l,j);
if i<r then sort(i,r);
end;
procedure insert(a:longint);
var p,np,q,nq:longint;
begin
inc(tot); np:=tot; p:=tail; x[np].len:=x[p].len+1; x[np].key:=1;
while (p<>0)and(x[p].tranc[a]=0) do
begin
x[p].tranc[a]:=np;
p:=x[p].fa;
end;
if x[p].tranc[a]=0
then x[p].tranc[a]:=np
else
begin
q:=x[p].tranc[a];
if x[q].len=x[p].len+1
then x[np].fa:=q
else
begin
inc(tot); nq:=tot; x[nq]:=x[q]; x[nq].key:=0;
x[nq].len:=x[p].len+1;
x[q].fa:=nq; x[np].fa:=nq;
while (x[p].tranc[a]=q) do
begin
x[p].tranc[a]:=nq;
p:=x[p].fa;
end;
end;
end;
tail:=np;
end;
procedure init(a,b:longint);
begin
w[len,1]:=b;
if w[a,2]=0 then w[a,2]:=len else w[w[a,1],2]:=len;
w[a,1]:=len; inc(len);
end;
procedure dfs(a:longint);
var tt:longint;
begin
tt:=w[a,2]; inc(len); pos[a]:=len;
if x[a].key=1 then y[n-x[a].len+1]:=a;
while tt<>0 do
begin
dep[w[tt,1]]:=dep[a]+1;
dfs(w[tt,1]);
tt:=w[tt,2];
end;
end;
function lca(a,b:longint):longint;
var i:longint;
begin
if dep[a]<dep[b] then begin i:=a; a:=b; b:=i; end;
for i:=20 downto 0 do
if dep[st[a,i]]>=dep[b]
then a:=st[a,i];
if a=b then exit(a);
for i:=20 downto 0 do
if st[a,i]<>st[b,i]
then begin a:=st[a,i]; b:=st[b,i]; end;
exit(st[a,0]);
end;
procedure solve(a:longint);
var tt:longint;
begin
tt:=w[a,2];
while tt<>0 do
begin
solve(w[tt,1]);
size[a]:=size[a]+size[w[tt,1]];
tt:=w[tt,2];
end;
sum:=sum+(int64(x[a].len-x[x[a].fa].len)*(size[a]-1)*(size[a]))div 2;
end;
begin
readln(n,m);
readln(stt); tot:=0; tail:=0;
for i:=n downto 1 do
insert(ord(stt[i])-96);
len:=tot+1;
for i:=1 to tot do
begin init(x[i].fa,i); st[i,0]:=x[i].fa; end;
len:=0; dep[0]:=1; dfs(0);
for j:=1 to 20 do
for i:=1 to tot do
st[i,j]:=st[st[i,j-1],j-1];
fillchar(size,sizeof(size),0);
for i:=1 to m do
begin
read(a); sum:=0; clear[0]:=1; clear[1]:=0;
for j:=1 to a do
begin read(z[j]); size[y[z[j]]]:=1; z[j]:=y[z[j]]; end;
sort(1,a);
top:=1; t[top]:=0;
for j:=1 to a do
begin
if z[j]=z[j-1] then continue;
tt:=lca(z[j],t[top]);
while dep[t[top]]>dep[tt] do
begin
if dep[t[top-1]]<=dep[tt]
then
begin
fa[t[top]]:=tt;
size[tt]:=size[tt]+size[t[top]];
dec(top);
if t[top]<>tt then begin inc(top); t[top]:=tt; inc(clear[0]); clear[clear[0]]:=tt; end;
break;
end;
fa[t[top]]:=t[top-1];
size[t[top-1]]:=size[t[top-1]]+size[t[top]];
dec(top);
end;
inc(top); t[top]:=z[j]; inc(clear[0]); clear[clear[0]]:=z[j];
end;
while top>1 do
begin
fa[t[top]]:=t[top-1];
size[t[top-1]]:=size[t[top-1]]+size[t[top]];
dec(top);
end;
sum:=0;
for j:=1 to clear[0] do
sum:=sum+(int64(x[clear[j]].len-x[fa[clear[j]]].len)*(size[clear[j]]-1)*size[clear[j]])div 2;
writeln(sum);
for j:=1 to clear[0] do
begin size[clear[j]]:=0; fa[clear[j]]:=0; end;
end;
end.