题目大意
给定$n$个字符串$S$,$m$次询问,每次询问给定两个字符串$s_1,s_2$,求$n$个字符串中有多少个串满足$s_1$是其前缀且$s_2$是其后缀。
$n\leq 2000,m\leq 10^5 \sum |S|,\sum (|s_1|+|s_2|) \leq 2\times 10^6$
题解
考虑正反建$Trie$树,原题就变为了在两棵子树中均出现的点有多少个。
你当然可以用主席树加二维数点解决,其实也可以将每一个串按照正向$Trie$树$Dfs$序排序,然后再反向建可持久化$Trie$,每次询问就先找到正向$dfs$序要求的区间,接着在可持久化$Trie$的两个对应的根中沿着$s_2$的反串得出答案。
复杂度为$O(n\log n+\sum |S|+\sum (|s_1|+|s_2|)+m\log n)$。
所以其实$n$甚至可以出成$10^5$级。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define M 2220000
#define N 2010
using namespace std;
namespace IO{
const int BS=(1<<19); int Top=0;
char OT[BS],*OS=OT,SS[20]; const char *fin=OT+BS-1;
void flush(){fwrite(OT,1,OS-OT,stdout);}
void Putchar(char c){*OS++ =c;if(OS==fin)flush(),OS=OT;}
void write(int x){
if(!x){Putchar('0');return;} if(x<0) x=-x,Putchar('-');
while(x) SS[++Top]=x%10,x/=10;
while(Top) Putchar(SS[Top]+'0'),--Top;
}
int read(){
int nm=0,fh=1; char cw=getchar();
for(;!isdigit(cw);cw=getchar()) if(cw=='-') fh=-fh;
for(;isdigit(cw);cw=getchar()) nm=nm*10+(cw-'0');
return nm*fh;
}
}using namespace IO;
char ch[M],*s[N],s1[M],s2[M]; int n,m,p[M][26],tg[N],len[N];
int sz[M],dfn[M],node[N],tot,Rt,rt[N];
int cnt,t[M][26],od[N],sum[M];
int ins(int &x,char *k,int rem){
if(!x) x=++tot; if(!rem) return x;
ins(t[x][k[0]-'a'],k+1,rem-1);
}
void dfs(int x){
if(!x) return; dfn[x]=++cnt,sz[x]=1;
for(int i=0;i<26;i++) dfs(t[x][i]),sz[x]+=sz[t[x][i]];
}
bool cmp(int x,int y){return dfn[node[x]]<dfn[node[y]];}
void ist(int &x,int pre,char *k,int rem){
sum[x=++cnt]=sum[pre]+1;
memcpy(p[x],p[pre],sizeof(p[x])); if(!rem) return;
ist(p[x][k[0]-'a'],p[pre][k[0]-'a'],k-1,rem-1);
}
int qry(int x,int pre,char *k,int rem){
if(sum[x]==sum[pre]) return 0; if(!rem) return sum[x]-sum[pre];
return qry(p[x][k[0]-'a'],p[pre][k[0]-'a'],k-1,rem-1);
}
void match(int &l,int &r,int x,char *k,int rem){
if(!rem){l=dfn[x],r=dfn[x]+sz[x]-1;return;}
match(l,r,t[x][k[0]-'a'],k+1,rem-1);
}
int fd(int tim){
int ls=1,rs=n,res=n+1,md;
while(ls<=rs){
md=((ls+rs)>>1);
if(dfn[node[od[md]]]>tim) rs=md-1;
else res=md,ls=md+1;
} return res;
}
int main(){
n=read(),s[0]=ch;
for(int i=1;i<=n;i++){
s[i]=s[i-1]+len[i-1],od[i]=i;
scanf("%s",s[i]),len[i]=strlen(s[i]);
node[i]=ins(Rt,s[i],len[i]);
} dfs(Rt),cnt=0,sort(od+1,od+n+1,cmp);
for(int i=1;i<=n;i++) ist(rt[i],rt[i-1],s[od[i]]+len[od[i]]-1,len[od[i]]);
for(int T=read(),ans=0,len1,len2,L,R;T;T--,write(ans),Putchar('\n')){
scanf("%s%s",s1,s2),len1=strlen(s1),len2=strlen(s2);
for(int i=0;i<len1;i++) s1[i]=(s1[i]-'a'+ans)%26+'a';
for(int i=0;i<len2;i++) s2[i]=(s2[i]-'a'+ans)%26+'a';
match(L,R,Rt,s1,len1); if(!R){ans=0;continue;}
L=fd(L-1),R=fd(R),ans=qry(rt[R],rt[L],s2+len2-1,len2);
}flush();return 0;
}