好久不写后缀树组了(好像以前也就写过一遍吧),各种奇葩出错。
实际上即使是后缀树组时间复杂度也是不对的。。为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