题目描述:
题目分析:
对
T
[
1...
m
]
T[1...m]
T[1...m]建广义后缀自动机,可持久化线段树合并维护
endpos
\texttt{endpos}
endpos 集合中哪个串最多,以及最多的出现次数。
定位
S
[
p
l
,
p
r
]
S[p_l,p_r]
S[pl,pr]在
T
T
T上的位置,具体地,把
S
S
S放到后缀自动机上匹配,求出每个前缀
S
[
1...
i
]
S[1...i]
S[1...i]匹配的最长后缀长度
p
l
e
n
[
i
]
plen[i]
plen[i],及其在后缀自动机上的对应位置
p
o
s
[
i
]
pos[i]
pos[i]。那么
p
o
s
[
p
r
]
pos[p_r]
pos[pr]的fail树上的祖先中深度最浅的
l
e
n
[
x
]
≥
p
r
−
p
l
+
1
len[x]\ge p_r-p_l+1
len[x]≥pr−pl+1的
x
x
x 就对应包含了
S
[
p
l
,
p
r
]
S[p_l,p_r]
S[pl,pr]。
在
x
x
x 的线段树中
[
l
,
r
]
[l,r]
[l,r] 查询即可。
注意广义后缀自动机中会存在 len[x]=len[y],而 fail[y] = x,所以此时不能按照 len 桶排序来确定顺序。
Code:
#include<bits/stdc++.h>
#define maxn 100005
#define maxp maxn*35
using namespace std;
void read(int &a){
char c;while(!isdigit(c=getchar()));
for(a=c-'0';isdigit(c=getchar());a=a*10+c-'0');
}
int n,m,Q;
char s[maxn*5],t[maxn];
int rt[maxn],lc[maxp],rc[maxp],tot;
struct node{
int sum,id;
bool operator < (const node &p)const{return sum==p.sum?id>p.id:sum<p.sum;}
}f[maxp];
void ins(int &i,int l,int r,int x){
if(!i) i=++tot;
if(l==r) {f[i]=(node){1,x};return;}
int mid=(l+r)>>1;
x<=mid?ins(lc[i],l,mid,x):ins(rc[i],mid+1,r,x);
f[i]=max(f[lc[i]],f[rc[i]]);
}
int merge(int x,int y,int l,int r){
if(!x||!y) return x+y;
int i=++tot,mid=(l+r)>>1;
if(l==r) {f[i]=(node){f[x].sum+f[y].sum,f[x].id};return i;}
lc[i]=merge(lc[x],lc[y],l,mid),rc[i]=merge(rc[x],rc[y],mid+1,r);
f[i]=max(f[lc[i]],f[rc[i]]);
return i;
}
node qry(int i,int l,int r,int x,int y){
if(!i) return (node){0,x};
if(x<=l&&r<=y) return f[i];
int mid=(l+r)>>1; node ret=(node){0,x};
if(x<=mid) ret=max(ret,qry(lc[i],l,mid,x,y));
if(y>mid) ret=max(ret,qry(rc[i],mid+1,r,x,y));
return ret;
}
int fa[maxn]={-1},ch[maxn][26],len[maxn],last,sz;
void extend(int c,int id){
int cur=++sz,p=last,q; len[last=cur]=len[p]+1,ins(rt[cur],1,m,id);
for(;~p&&!ch[p][c];p=fa[p]) ch[p][c]=cur;
if(p==-1) fa[cur]=0;
else if(len[q=ch[p][c]]==len[p]+1) fa[cur]=q;
else{
int clone=++sz; len[clone]=len[p]+1,memcpy(ch[clone],ch[q],sizeof ch[q]);
fa[clone]=fa[q],fa[cur]=fa[q]=clone;
for(;~p&&ch[p][c]==q;p=fa[p]) ch[p][c]=clone;
}
}
int pos[maxn*5],pL[maxn*5],F[17][maxn];
vector<int>G[maxn];
void dfs(int u){for(int i=G[u].size()-1,v;i>=0;i--) dfs(v=G[u][i]),F[0][v]=u,rt[u]=merge(rt[u],rt[v],1,m);}
int main()
{
scanf("%s%d",s+1,&m);
for(int i=1;i<=m;i++){
scanf("%s",t+1),last=0;
for(int j=1;t[j];j++) extend(t[j]-'a',i);
}
for(int i=1;i<=sz;i++) G[fa[i]].push_back(i);
dfs(0);
for(int j=1;j<=16;j++) for(int i=1;i<=sz;i++) F[j][i]=F[j-1][F[j-1][i]];
for(int i=1,x=0,Len=0,c;s[i];i++){
c=s[i]-'a'; while(x&&!ch[x][c]) Len=len[x=fa[x]];
if(ch[x][c]) x=ch[x][c],Len++;
pos[i]=x,pL[i]=Len;
}
read(Q);
for(int l,r,L,R,Len;Q--;){
read(l),read(r),read(L),read(R);
if((Len=R-L+1)>pL[R]) {printf("%d 0\n",l);continue;}
int x=pos[R];
for(int i=16;i>=0;i--) if(len[F[i][x]]>=Len) x=F[i][x];
node ret=qry(rt[x],1,m,l,r);
printf("%d %d\n",ret.id,ret.sum);
}
}