#include <stdio.h>
int main()
{
puts("转载请注明出处谢谢");
puts("http://blog.csdn.net/vmurder/article/details/43015849");
}
题意:
n,m
n个串
m个串
样例里面倒数第二行的you应该扔到下一行。
问m个串每个在前n个串中的几个出现过。
题解:
首先这道题跟
是一样的,只不过更卡时一点,或者说喵的数据太弱。
这道题虽然是后缀自动机,但是大体思路和
【BZOJ2434】【NOI2011】阿狸的打字机 AC自动机
是一样的。都是dfs序+树状数组优化
好了,说这道题。
就是我们建广义后缀树【就是多串的反序后缀自动机】
然后根据dfs序快速转移,用树状数组维护某区间有多少个不同的串。
我来贴两个详细的 题解 网址
16bitwar:http://blog.csdn.net/jiangyuze831/article/details/42964105
wyfcyx:http://wyfcyx.is-programmer.com/posts/76391.html
代码:
#include <map>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 201000
#define T 26
using namespace std;
struct Suffix_Tree // 广义后缀树
{
int head[N],next[N],v[N],cnt;
void add(int u,int _v)
{
v[++cnt]=_v;
next[cnt]=head[u];
head[u]=cnt;
}
int in[N],out[N],dfn,stk[N];
void build_dfn(int x)
{
in[x]=++dfn;
stk[dfn]=x;
for(int i=head[x];i;i=next[i])
build_dfn(v[i]);
out[x]=dfn;
}
}sft,belong;
struct QUERY
{
int id,p;
QUERY(int _id=0,int _p=0):id(_id),p(_p){}
bool operator < (const QUERY &a)const
{return sft.out[p]<sft.out[a.p];}
}ask[N];
int vis[N],ans[N];
char s[N];
int n,m;
struct FENWICK
{
int a[N],cnt[N];
void add(int p,int x){for(;p<N;p+=p&-p)a[p]+=x;}
int query(int p)
{
int ans=0,temp=p;
for(p=sft.out[temp] ;p;p-=p&-p)ans+=a[p];
for(p=sft.in[temp]-1;p;p-=p&-p)ans-=a[p];
return ans;
}
}fw;
struct SAM // 广义后缀自动机
{
map<int,int>next[N];
int pa[N],deep[N];
int root,last,cnt;
int newnode(int dep){deep[++cnt]=dep;return cnt;}
void init(){root=last=cnt=1;}
void add(char alp,int id) // 建立广义后缀自动机
{
int np=next[last][alp];
if(np)
{
if(deep[np]==deep[last]+1)last=np;
else {
int nq=newnode(deep[last]+1);
pa[nq]=pa[np],pa[np]=nq;
next[nq]=next[np];
int p=last;
while(p&&next[p][alp]==np)
next[p][alp]=nq,p=pa[p];
last=nq;
}
}
else {
np=newnode(deep[last]+1);
int p=last;
while(p&&!next[p][alp])next[p][alp]=np,p=pa[p];
if(!p)pa[np]=root;
else {
int q=next[p][alp];
if(deep[q]==deep[p]+1)pa[np]=q;
else {
int nq=newnode(deep[p]+1);
pa[nq]=pa[q],pa[q]=pa[np]=nq;
next[nq]=next[q];
while(p&&next[p][alp]==q)
next[p][alp]=nq,p=pa[p];
}
}
last=np;
}
belong.add(last,id);
}
void build_sft(){for(int i=2;i<=cnt;i++)sft.add(pa[i],i);}
void deal_query()
{
bool find;
int i,j,p;
for(int i=1;i<=m;i++)
{
scanf("%s",s),find=1;
for(p=root,j=0;s[j];j++)
{
if(!next[p][s[j]]){find=0;break;}
p=next[p][s[j]];
}
if(find)ask[i]=QUERY(i,p);
else ask[i]=QUERY(i,-1);
}
sort(ask+1,ask+m+1);
}
}sam;
int main()
{
// freopen("test.in","r",stdin);
int i,j,k;
scanf("%d%d",&n,&m);
sam.init();
for(i=1;i<=n;i++)
{
scanf("%s",s);
sam.last=sam.root;
for(j=0;s[j];j++)sam.add(s[j],i);
}
sam.build_sft();
sft.build_dfn(1);
sam.deal_query();
for(k=1;k<=m&&ask[k].p==-1;k++);
for(j=1;j<=sam.cnt;j++)
{
int u=sft.stk[j];
for(i=belong.head[u];i;i=belong.next[i])
{
int v=belong.v[i];
fw.add(j,1);
if(vis[v])fw.add(vis[v],-1);
vis[v]=j;
}
while(sft.out[ask[k].p]==j)
{
ans[ask[k].id]=fw.query(ask[k].p);
k++;
}
}
for(i=1;i<=m;i++)printf("%d\n",ans[i]);
return 0;
}