题意
n
≤
100000
n\le100000
n≤100000
分析
题目相当于求询问串与母串的第一个匹配位置之前所有后缀的lcp的和。
对母串建sam,把每个节点的right集用线段树合并求出来,然后把询问串在上面跑顺便统计答案就好了。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
typedef long long LL;
const int N=100005;
int n,m,sz,tot,fa[N*2],ch[N*2][10],mx[N*2],last,rt[N*2],b[N*2],c[N*2],pos[N];
char str[N];
struct tree{int l,r,s;}t[N*40];
void extend(int x)
{
int p,q,np,nq;
p=last;last=np=++tot;mx[np]=mx[p]+1;
for (;p&&!ch[p][x];p=fa[p]) ch[p][x]=np;
if (!p) fa[np]=1;
else
{
q=ch[p][x];
if (mx[q]==mx[p]+1) fa[np]=q;
else
{
nq=++tot;mx[nq]=mx[p]+1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[nq]=fa[q];fa[q]=fa[np]=nq;
for (;ch[p][x]==q;p=fa[p]) ch[p][x]=nq;
}
}
}
void ins(int &d,int l,int r,int x)
{
if (!d) d=++sz;
t[d].s++;
if (l==r) return;
int mid=(l+r)/2;
if (x<=mid) ins(t[d].l,l,mid,x);
else ins(t[d].r,mid+1,r,x);
}
int merge(int x,int y)
{
if (!x||!y) return x^y;
int p=++sz;
t[p].l=merge(t[x].l,t[y].l);
t[p].r=merge(t[x].r,t[y].r);
t[p].s=t[x].s+t[y].s;
return p;
}
int get_fir(int d,int l,int r)
{
if (l==r) return l;
int mid=(l+r)/2;
if (t[t[d].l].s) return get_fir(t[d].l,l,mid);
else return get_fir(t[d].r,mid+1,r);
}
int query(int d,int l,int r,int x,int y)
{
if (!d||x<=l&&r<=y) return t[d].s;
int mid=(l+r)/2;
if (y<=mid) return query(t[d].l,l,mid,x,y);
else if (x>mid) return query(t[d].r,mid+1,r,x,y);
else return query(t[d].l,l,mid,x,y)+query(t[d].r,mid+1,r,x,y);
}
void pre()
{
for (int i=1;i<=tot;i++) b[mx[i]]++;
for (int i=1;i<=n;i++) b[i]+=b[i-1];
for (int i=1;i<=tot;i++) c[b[mx[i]]--]=i;
for (int i=1;i<=n;i++) ins(rt[pos[i]],1,n,i);
for (int i=tot;i>1;i--) rt[fa[c[i]]]=merge(rt[fa[c[i]]],rt[c[i]]);
}
int main()
{
scanf("%d%s",&n,str+1);
last=tot=1;
for (int i=1;i<=n;i++) extend(str[i]-'0'),pos[i]=last;
pre();
scanf("%d",&m);
while (m--)
{
scanf("%s",str+1);
int len=strlen(str+1),x=1;
LL ans=0;
bool flag=0;
for (int i=1;i<=len;i++) x=ch[x][str[i]-'0'];
if (!x)
{
x=1;
for (int i=1;i<=len;i++) x=ch[x][str[i]-'0'],ans+=t[rt[x]].s;
printf("%lld\n",ans+n);
}
else
{
int p=get_fir(rt[x],1,n)-len+1;
x=1;
for (int i=1;i<=len;i++) x=ch[x][str[i]-'0'],ans+=query(rt[x],1,n,1,p+i-1);
printf("%lld\n",ans+p-1);
}
}
return 0;
}