SAM好题,显然我们不能与每个后缀都去算LCP

考虑对询问串每一位算贡献,先构建出逆序构建自动机,这样我们得到了原串的后缀树(parent树)

根据parent树的定义,一个节点对应字符串出现的位置对应该节点的right集合也就是子树right集合的并

某些节点代表了一个后缀,我们从开头到结尾编号为1~n;这样求出每个节点的子树内,代表后缀的节点所代表的后缀编号最小是多少,记作mi[]

然后对于每个询问串在自动机上匹配(逆序),设最终匹配到的点为x

由于每个子串一定是某个后缀的某个前缀

如果匹配成功了,说明匹配到mi[x]这个后缀就结束了,否则会一直匹配下去,我们假设匹配到n+1结束

设最终匹配到的后缀为m,显然,从x到root上我们计算每条边的贡献

对于边(fa[a],a),边上的每个字符的比较次数贡献显然就是a子树内代表后缀编号小于等于m的节点个数

裸的想法可以用dfs序+主席树来完成

最后我们答案还要+x-1,因为比较失败也算是一次比较……

 type node=record
po,next:longint;
end;
point=record
l,r,s:longint;
end; var tree:array[..*] of point;
e:array[..] of node;
go:array[..,''..''] of longint;
mi,b,h,p,l,r,fa,mx,w:array[..] of longint;
cl,n,m,x,y,i,j,k,last,t,len:longint;
fl:boolean;
s:ansistring;
ans:int64; function lowbit(x:longint):longint;
begin
exit(x and (-x));
end; function min(a,b:longint):longint;
begin
if a>b then exit(b) else exit(a);
end; procedure ins(x,y:longint);
begin
inc(len);
e[len].po:=y;
e[len].next:=p[x];
p[x]:=len;
end; procedure add(c:char);
var p,q,np,nq:longint;
begin
p:=last;
inc(t); np:=t; last:=t;
mx[np]:=mx[p]+;
w[np]:=i;
while (p<>) and (go[p,c]=) do
begin
go[p,c]:=np;
p:=fa[p];
end;
if p= then fa[np]:=
else begin
q:=go[p,c];
if mx[q]=mx[p]+ then fa[np]:=q
else begin
inc(t); nq:=t;
mx[nq]:=mx[p]+;
go[nq]:=go[q];
fa[nq]:=fa[q];
fa[q]:=nq; fa[np]:=nq;
while go[p,c]=q do
begin
go[p,c]:=nq;
p:=fa[p];
end;
end;
end;
end; procedure dfs(x:longint);
var i,y:longint;
begin
inc(len);
b[len]:=x;
mi[x]:=w[x];
if w[x]= then mi[x]:=;
// writeln(x,' ',fa[x],':',w[x]);
l[x]:=len;
i:=p[x];
while i<> do
begin
y:=e[i].po;
dfs(y);
mi[x]:=min(mi[x],mi[y]);
i:=e[i].next;
end;
r[x]:=len;
// writeln(mi[x]);
end; function build(l,r:longint):longint;
var m,q:longint;
begin
inc(len);
if l=r then exit(len)
else begin
q:=len;
m:=(l+r) shr ;
tree[q].l:=build(l,m);
tree[q].r:=build(m+,r);
exit(q);
end;
end; function work(l,r,last,x:longint):longint;
var m,q:longint;
begin
inc(len);
q:=len;
if l=r then tree[q].s:=tree[last].s+
else begin
m:=(l+r) shr ;
if x<=m then
begin
tree[q].r:=tree[last].r;
tree[q].l:=work(l,m,tree[last].l,x);
end
else begin
tree[q].l:=tree[last].l;
tree[q].r:=work(m+,r,tree[last].r,x);
end;
tree[q].s:=tree[tree[q].l].s+tree[tree[q].r].s;
end;
exit(q);
end; function ask(l,r,p,q:longint):longint;
var m:longint;
begin
if (x>=r) then exit(tree[q].s-tree[p].s)
else begin
m:=(l+r) shr ;
if x<=m then exit(ask(l,m,tree[p].l,tree[q].l))
else exit(tree[tree[q].l].s-tree[tree[p].l].s+ask(m+,r,tree[p].r,tree[q].r));
end;
end; begin
readln(n);
readln(s);
last:=; t:=;
for i:=n downto do
add(s[i]);
for i:= to t do
if fa[i]<> then ins(fa[i],i);
len:=;
dfs();
readln(m);
len:=;
h[]:=build(,n);
for i:= to t do
if w[b[i]]= then h[i]:=h[i-]
else h[i]:=work(,n,h[i-],w[b[i]]);
for i:= to m do
begin
readln(s);
len:=length(s);
j:=;
fl:=true;
cl:=;
for k:=len downto do
if go[j,s[k]]= then
begin
while (go[j,s[k]]=) and (j>) do
begin
j:=fa[j];
cl:=mx[j];
end;
if j= then j:=
else begin
inc(cl);
j:=go[j,s[k]];
end;
fl:=false;
end
else begin
inc(cl);
j:=go[j,s[k]];
end; //cl表示询问串从头开始最长匹配的长度
if fl then x:=mi[j] else x:=n+;
ans:=;
if j> then
begin
y:=cl-mx[fa[j]]; // 这里要注意
ans:=ans+int64(y)*int64(ask(,n,h[l[j]-],h[r[j]]));
j:=fa[j];
end;
while j> do
begin
y:=mx[j]-mx[fa[j]];
ans:=ans+int64(y)*int64(ask(,n,h[l[j]-],h[r[j]]));
j:=fa[j];
end;
writeln(ans+x-);
end;
end.

bzoj3413的更多相关文章

  1. 【BZOJ3413】匹配(后缀自动机,线段树合并)

    [BZOJ3413]匹配(后缀自动机,线段树合并) 题面 BZOJ 题解 很好的一道题目. 做一个转化,匹配的次数显然就是在可以匹配的区间中,每个前缀的出现次数之和. 首先是空前缀的出现次数,意味着你 ...

  2. 【BZOJ3413】匹配 离线+后缀树+树状数组

    [BZOJ3413]匹配 Description Input 第一行包含一个整数n(≤100000). 第二行是长度为n的由0到9组成的字符串. 第三行是一个整数m. 接下来m≤5·10行,第i行是一 ...

  3. BZOJ3413 : 匹配

    FDUSC前刷刷题吧.. 本题每个询问就是说将询问串与主串每个后缀匹配,若匹配成功则结束,否则加上lcp的长度 对主串建立后缀树,并用主席树维护DFS序 对于每个询问串,找到最后走到的点fin_nod ...

  4. BZOJ3413: 匹配(后缀自动机 线段树合并)

    题意 题目链接 Sol 神仙题Orz 后缀自动机 + 线段树合并... 首先可以转化一下模型(想不到qwq):问题可以转化为统计\(B\)中每个前缀在\(A\)中出现的次数.(画一画就出来了) 然后直 ...

  5. BZOJ3413: 匹配(后缀自动机,Parent树,线段树合并)

    Description Input 第一行包含一个整数n(≤100000). 第二行是长度为n的由0到9组成的字符串. 第三行是一个整数m. 接下来m≤5·10行,第i行是一个由0到9组成的字符串s, ...

随机推荐

  1. UIDynamic仿物理引擎-浮动碰撞效果-b

    最近产品提了个需求(电商的APP-两鲜),需要在APP背景加上几个水果图案在那里无规则缓慢游荡...模仿 天天果园 APP的.好吧,那我就在网上找了很多文章,总结一下写个demo.效果如下: Mou ...

  2. 编译dubbo2.5.4时遇到的问题及解决

    dubbo的官方git地址为:https://github.com/alibaba/dubbo 按照其流程进行下载及编译,遇到的问题为: 1. 执行 mvn clean install -Dmaven ...

  3. Feature Extraction

    http://www.erogol.com/ml-work-flow-part-3-feature-extraction/

  4. iOS$299企业账号In House ipa发布流程

    1.在Mac系统中进入“钥匙串访问”,选择“钥匙串访问”-“证书助理”-“从证书颁发机构请求证书”. 填写前两项,并保存在本地. 2.登录https://developer.apple.com,进入i ...

  5. oracle 删除用户,表空间;循环删除表

    select * from dba_tablespaces 说明:查看所有表空间 ----------------------------------------------------------- ...

  6. FACL的使用

    ACL的使用 ACL即Access Control List 主要的目的是提供传统的owner,group,others的read,write,execute权限之外的具体权限设置,ACL可以针对单一 ...

  7. 【POJ】【1704】Georgia and Bob

    组合游戏 Nim游戏的一个变形 题解请看金海峰的博客 以下为引用: 分析:我们把棋子按位置升序排列后,从后往前把他们两两绑定成一对.如果总个数是奇数,就把最前面一个和边界(位置为0)绑定. 在同一对棋 ...

  8. WinForm点击按钮在对应的panel里画图

    panel在form1里,button在form1上方,panel在下面. 主要是在button1的click时间获取panel的画笔. 下面的不行,在panel里获取画笔,然后传到button1,根 ...

  9. failed creating the Direct3d device--debug

    D3DDEVTYPE_REF 使用REF设备,用软件模拟Direct3D API 照理说是为了让电脑能跑本机不能硬件执行的渲染命令的 但我 pDeviceSettings->d3d9.Devic ...

  10. WinForm 中ComboBox 绑定总结

    1.DataTable绑定 用DataTable直接绑定,只需要设置DataSource.DisplayMember.ValueMember三个属性即可. this.cmbConsume.DataSo ...