先建出AC自动机,即求其fail树上,$s_{l},s_{l+1},...,s_{r}$这些串的位置的子树中有多少个$k$的前缀
对$[l,r]$区间分块(设块大小为$k$),询问分为块内和块外两部分:
对于块内,直接统计每一个块对每一个$s_{k}$的答案,枚举每一个块,问题可以看作对于每一个$k$的前缀求其到根路径上有多少个串,dfs一下即可处理(一起dfs求出所有位置的答案,再枚举$s_{k}$),时间复杂度为$o(\frac{n^{2}}{k})$
对于块外,先枚举$s_{k}$,然后单点修改+子树查询,线段树维护即可,时间复杂度为$o(nk\log_{2}n)$
取$k=\sqrt{\frac{n}{\log_{2}n}}$最优,时间复杂度为$o(n\sqrt{n\log_{2}n})$
(好像也可以直接数链剖分+可持久化线段树来做,复杂度为两个log)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 100005 4 #define K 200 5 #define NK 505 6 #define ll long long 7 #define L (k<<1) 8 #define R (L+1) 9 #define mid (l+r>>1) 10 struct ji{ 11 int nex,to; 12 }edge[N]; 13 struct qu{ 14 int l,r,id; 15 }; 16 queue<int>q; 17 vector<int>pos[N]; 18 vector<qu>v[N]; 19 int V,E,n,m,l,r,k,len[N],nex[N],ch[N][26],head[N],dfn[N],sz[N],sum[N],st[NK],ed[NK],bl[N],g[NK][N],f[N<<2]; 20 char s[N]; 21 ll ans[N]; 22 void add(int x,int y){ 23 edge[E].nex=head[x]; 24 edge[E].to=y; 25 head[x]=E++; 26 } 27 void build(){ 28 for(int i=0;i<26;i++) 29 if (ch[1][i]){ 30 nex[ch[1][i]]=1; 31 q.push(ch[1][i]); 32 } 33 while (!q.empty()){ 34 int k=q.front(); 35 q.pop(); 36 add(nex[k],k); 37 for(int i=0;i<26;i++) 38 if (ch[k][i]){ 39 int ans=nex[k]; 40 while ((ans>1)&&(!ch[ans][i]))ans=nex[ans]; 41 if (!ch[ans][i])nex[ch[k][i]]=ans; 42 else nex[ch[k][i]]=ch[ans][i]; 43 q.push(ch[k][i]); 44 } 45 } 46 } 47 void dfs(int k){ 48 sz[k]=1; 49 dfn[k]=++l; 50 for(int i=head[k];i!=-1;i=edge[i].nex){ 51 dfs(edge[i].to); 52 sz[k]+=sz[edge[i].to]; 53 } 54 } 55 void tot(int k){ 56 for(int i=head[k];i!=-1;i=edge[i].nex){ 57 sum[edge[i].to]+=sum[k]; 58 tot(edge[i].to); 59 } 60 } 61 void update(int k,int l,int r,int x,int y){ 62 f[k]+=y; 63 if (l==r)return; 64 if (x<=mid)update(L,l,mid,x,y); 65 else update(R,mid+1,r,x,y); 66 } 67 int query(int k,int l,int r,int x,int y){ 68 if ((l>y)||(x>r))return 0; 69 if ((x<=l)&&(r<=y))return f[k]; 70 return query(L,l,mid,x,y)+query(R,mid+1,r,x,y); 71 } 72 int main(){ 73 scanf("%d%d",&n,&m); 74 V=1; 75 for(int i=1;i<=n;i++){ 76 scanf("%s",s); 77 len[i]=strlen(s); 78 for(int j=0,k=1;s[j];j++){ 79 if (!ch[k][s[j]-'a'])ch[k][s[j]-'a']=++V; 80 k=ch[k][s[j]-'a']; 81 pos[i].push_back(k); 82 } 83 } 84 memset(head,-1,sizeof(head)); 85 build(); 86 for(int i=1;i<=n;i++){ 87 bl[i]=(i-1)/K+1; 88 if (!st[bl[i]])st[bl[i]]=i; 89 ed[bl[i]]=i; 90 } 91 dfs(1); 92 for(int i=1;i<=bl[n];i++){ 93 memset(sum,0,sizeof(sum)); 94 for(int j=st[i];j<=ed[i];j++)sum[pos[j][len[j]-1]]++; 95 tot(1); 96 for(int j=1;j<=n;j++) 97 for(int k=0;k<len[j];k++)g[i][j]+=sum[pos[j][k]]; 98 } 99 for(int i=1;i<=m;i++){ 100 scanf("%d%d%d",&l,&r,&k); 101 if (bl[l]==bl[r])v[k].push_back(qu{l,r,i}); 102 else{ 103 v[k].push_back(qu{l,ed[bl[l]],i}); 104 v[k].push_back(qu{st[bl[r]],r,i}); 105 for(int j=bl[l]+1;j<bl[r];j++)ans[i]+=g[j][k]; 106 } 107 } 108 for(int i=1;i<=n;i++){ 109 for(int j=0;j<len[i];j++)update(1,1,V,dfn[pos[i][j]],1); 110 for(int j=0;j<v[i].size();j++) 111 for(int k=v[i][j].l;k<=v[i][j].r;k++){ 112 int kk=pos[k][len[k]-1]; 113 ans[v[i][j].id]+=query(1,1,V,dfn[kk],dfn[kk]+sz[kk]-1); 114 } 115 for(int j=0;j<len[i];j++)update(1,1,V,dfn[pos[i][j]],-1); 116 } 117 for(int i=1;i<=m;i++)printf("%lld\n",ans[i]); 118 }View Code