Description
给出n个字符串Si,m次询问,第i次询问Sli~Sri这些字符串中有多少个是字符串pi的母串。
∑|Si|,∑|pi|<=5∗105
Solution
看到多串匹配就想到了AC自动机。
然而辛辛苦苦打完之后发现只有自己傻傻地写的那么辣鸡。
在线OrzSAM和SA分块做法。
显然我们需要离线回答。
把所有的pi建一棵AC自动机。
然后把询问差分,变成前缀的形式。
那么我们只需要每次把一个主串放在AC自动机上跑一跑,然后把经过的点和它在fail树中到根的路径全部+1.但是每个点只会加一次(因为没让你统计出现次数)
于是我们可以把这个操作用树状数组维护dfs序的形式来完成。
如果我们按dfs序的顺序进行修改操作,那么x和la所重复的路径一定是lca(x,la)到根的这段路。
那么我们可以求出所有点然后按dfs序排序,然后操作。
也就是说我们要兹瓷修改一个点到根的路径,以及单点查询。
那么我们可以这样做:如果一个操作y对点x有影响,那么y一定存在于x的子树当中。
于是我们这个东西等价于单点修改,子树询问。
然后这道题就解决了。
那些让C++选手去写vector的出题人都应该拖出去续了
Code
#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define rep(i,a) for(int i=la[a];i;i=ne[i])
#define N 500005
using namespace std;
typedef vector<char> vec;
struct note{int x,bz,id,p;}a[N*2];
bool cmp(note x,note y) {return x.x<y.x;}
int t[N][26],next[N],d[N],h[N],dfn[N],cout[N],an[N],tr[N];
int to[N],ne[N],la[N],in[N],out[N],p[N],f[N][19],deep[N];
int n,m,x,y,le,ri,tot,top,bz,l;
vec s[N];
char st[N];
bool cmd(int x,int y) {return in[x]<in[y];}
void link(int x,int y) {
to[++l]=y;ne[l]=la[x];la[x]=l;
}
void insert(int x,int y) {
for(;x<=tot;x+=x&-x) tr[x]+=y;
}
int query(int x) {
int ans=0;
for(;x;x-=x&-x) ans+=tr[x];
return ans;
}
void makefail() {
int i=0,j=1;d[1]=1;
while (i<j) {
i++;
fo(k,0,25) if (t[d[i]][k]) {
int x=t[d[i]][k];
if (d[i]!=1) {
int y=next[d[i]];
while (y&&!t[y][k]) y=next[y];
if (y) next[x]=t[y][k];
else next[x]=1;
} else next[x]=1;
link(next[x],x);
d[++j]=x;
}
}
}
void add(vec s) {
int x=1;
fo(i,0,s.size()-1) {
int y=s[i]-'a';
while (x&&!t[x][y]) x=next[x];
x=t[x][y];if (!x) x=1;p[++p[0]]=x;
}
}
void dfs(int x) {
in[x]=++tot;f[x][0]=next[x];deep[x]=deep[next[x]]+1;
fo(j,1,18) f[x][j]=f[f[x][j-1]][j-1];
rep(i,x) dfs(to[i]);
out[x]=tot;
}
int lca(int x,int y) {
if (deep[x]<deep[y]) swap(x,y);
fd(j,18,0) if (deep[f[x][j]]>deep[y]) x=f[x][j];
if (deep[x]!=deep[y]) x=f[x][0];
fd(j,18,0) if (f[x][j]!=f[y][j]) x=f[x][j],y=f[y][j];
if (x!=y) return f[x][0]; else return x;
}
int main() {
scanf("%d%d",&n,&m);top=1;
fo(i,1,n) {
scanf("%s",st);
fo(j,0,strlen(st)-1) s[i].push_back(st[j]);
}
fo(i,1,m) {
scanf("%d%d%s",&le,&ri,st);int x=1;
fo(j,0,strlen(st)-1) {
int y=st[j]-'a';
if (!t[x][y]) t[x][y]=++top;x=t[x][y];
}
a[++tot].x=le-1;a[tot].bz=-1;a[tot].id=i;a[tot].p=x;
a[++tot].x=ri;a[tot].bz=1;a[tot].id=i;a[tot].p=x;
}
sort(a+1,a+tot+1,cmp);makefail();tot=0;
dfs(1);int j=0;while (!a[j+1].x) j++;
fo(i,1,n) {
p[0]=0;add(s[i]);sort(p+1,p+p[0]+1,cmd);
fo(k,1,p[0]) {
insert(in[p[k]],1);
if (k!=1) insert(in[lca(p[k-1],p[k])],-1);
}
while (a[j+1].x==i) j++,an[a[j].id]+=a[j].bz*(query(out[a[j].p])-query(in[a[j].p]-1));
}
fo(i,1,m) printf("%d\n",an[i]);
}