好久不写后缀树组了(好像以前也就写过一遍吧),各种奇葩出错。
实际上即使是后缀树组时间复杂度也是不对的。。为O(M*Len)。另外AC自动机也可做,时间复杂度还是不对。。(可能可以用树上的一些结构来统计保证时间复杂度,但具体没有想过)。
首先将姓名和点名串用间隔符连起来跑后缀树组(sam应该也行,但是后面完全不一样)。把点名串也加进去的话方便找到点名串的位置。找到点名串的位置以后只要height值>点名串的长度就可以不断向前后拓展,然后更新答案。
AC代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 300005
using namespace std;
int n,m,cnt,mx,sa[N],hgt[N],rnk[N],t[N],sum[N*4],blg[N],a[N],sta[N],val[N],l[N],ans[N];
int read(){
int x=0; char ch=getchar();
while (ch<'0' || ch>'9') ch=getchar();
while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); }
return x;
}
void getsa(){
int i,k,now=0;
for (i=1; i<=n; i++) sum[a[i]]++;
for (i=1; i<=mx; i++) sum[i]+=sum[i-1];
for (i=n; i; i--) sa[sum[a[i]]--]=i;
for (i=1; i<=n; i++){ rnk[sa[i]]=rnk[sa[i-1]]; if (i<2 || a[sa[i]]!=a[sa[i-1]]) rnk[sa[i]]++; }
for (k=1; now<n; k<<=1){
for (i=1; i<=k; i++) t[i]=n-k+i;
for (i=1; i<=n; i++) sum[i]=0;
for (i=1; i<=n-k; i++) sum[rnk[i+k]]++;
sum[1]+=k; for (i=2; i<=n; i++) sum[i]+=sum[i-1];
for (i=n; i>k; i--) t[sum[rnk[i]]--]=i-k;
for (i=1; i<=n; i++) sum[i]=0;
for (i=1; i<=n; i++) sum[rnk[i]]++;
for (i=2; i<=n; i++) sum[i]+=sum[i-1];
for (i=n; i; i--) sa[sum[rnk[t[i]]]--]=t[i];
now=0; memcpy(t,rnk,sizeof(rnk));
for (i=1; i<=n; i++){
if (i==1 || t[sa[i]]!=t[sa[i-1]] || t[sa[i]+k]!=t[sa[i-1]+k]) now++; rnk[sa[i]]=now;
}
}
}
void gethgt(){
int i,j,k=0;
for (i=1; i<=n; i++){
if (k) k--; if (rnk[i]==1){ hgt[1]=0; continue; }
for (j=sa[rnk[i]-1]; a[i+k]==a[j+k]; k++); hgt[rnk[i]]=k;
}
}
int solve(int k,int x){
int c=blg[sa[x]]; if (!c || val[c]==k) return 0;
val[c]=k; ans[c]++; return 1;
}
int main(){
cnt=read(); m=read(); int i,j; mx=1000000;
for (i=1; i<=cnt; i++) for (j=0; j<2; j++){
int slen=read(); while (slen--){ a[++n]=read(); blg[n]=i; }
a[++n]=++mx;
}
for (i=1; i<=m; i++){
int slen=read(); l[i]=slen; sta[i]=n+1;
while (slen--) a[++n]=read(); a[++n]=++mx;
}
getsa(); gethgt();
for (i=1; i<=m; i++){
int tmp=0;
for (j=rnk[sta[i]]; j; j--){ tmp+=solve(i,j); if (hgt[j]<l[i]) break; }
for (j=rnk[sta[i]]+1; j<=n && hgt[j]>=l[i]; j++) tmp+=solve(i,j);
printf("%d\n",tmp);
}
for (i=1; i<cnt; i++) printf("%d ",ans[i]); printf("%d\n",ans[cnt]);
return 0;
}
by lych
2016.2.11