给你一个串\(S\),以及一个字符串数组\(T_{1,2,...m}\),\(q\)次询问,每次问\(S\)的子串\(S[p_l,...p_r]\)在\(T_{l...r}\)中的哪个串的出现次数最多,并输出出现次数。
做法:
对串\(S\)和数组\(T\)建立后缀自动机。
在后缀自动机上找到\(S[l,r]\)这个子串对应的节点u,这是一个经典操作。
数组\(T\)内每个字符串都可以视作一种颜色。
现在问题转变为,每次询问一个节点,节点的link树子树内部哪种颜色出现次数最多,这个次数是多少。
这里可以线段树合并,或者树上启发式合并来做。
这里选择用线段树合并的做法。
时间复杂度\(O(nlogn)\)。
#include<bits/stdc++.h> using namespace std; const int maxn=6e5+10; int m,q; int n,len[maxn<<1],link[maxn<<1],nxt[maxn<<1][26],tot=1,lst=1; string s; string t[maxn]; void sam_extend (char c) { int cur=++tot,p=lst; len[cur]=len[lst]+1; while (p&&!nxt[p][c-'a']) { nxt[p][c-'a']=cur; p=link[p]; } if (!p) link[cur]=1; else { int q=nxt[p][c-'a']; if (len[p]+1==len[q]) { link[cur]=q; } else { int clone=++tot; len[clone]=len[p]+1; for (int i=0;i<26;i++) { nxt[clone][i]=nxt[q][i]; } link[clone]=link[q]; while (p&&nxt[p][c-'a']==q) { nxt[p][c-'a']=clone; p=link[p]; } link[q]=link[cur]=clone; } } lst=cur; } const int M=maxn*40; int c[M],id[M],lson[M],rson[M],tol,T[maxn<<1]; int up (int u,int l,int r,int p,int v) { if (!u) u=++tol; if (l==r) { c[u]+=v; id[u]=l; return u; } int mid=(l+r)>>1; if (p<=mid) lson[u]=up(lson[u],l,mid,p,v); if (p>mid) rson[u]=up(rson[u],mid+1,r,p,v); c[u]=max(c[lson[u]],c[rson[u]]); if (c[rson[u]]==c[u]) id[u]=id[rson[u]]; if (c[lson[u]]==c[u]) id[u]=id[lson[u]]; return u; } int merge (int x,int y,int l,int r) { if (!x||!y) return x+y; int u=++tol; if (l==r) { c[u]=c[x]+c[y]; id[u]=l; return u; } int mid=(l+r)>>1; lson[u]=merge(lson[x],lson[y],l,mid); rson[u]=merge(rson[x],rson[y],mid+1,r); c[u]=max(c[lson[u]],c[rson[u]]); if (c[rson[u]]==c[u]) id[u]=id[rson[u]]; if (c[lson[u]]==c[u]) id[u]=id[lson[u]]; return u; } pair<int,int> query (int u,int l,int r,int L,int R) { //printf("%d %d %d %d %d\n",u,l,r,L,R); if (L>R) return make_pair(0,0); if (l>=L&&r<=R) { return make_pair(c[u],id[u]); } int mid=(l+r)>>1; pair<int,int> ans=make_pair(0,0); if (L<=mid) ans=query(lson[u],l,mid,L,R); if (R>mid) { pair<int,int> tt=query(rson[u],mid+1,r,L,R); if (tt.first>ans.first) { ans.first=tt.first; ans.second=tt.second; } } return ans; } vector<int> g[maxn<<1]; int father[25][maxn<<1]; void dfs (int u) { for (int i=1;i<=20;i++) father[i][u]=father[i-1][father[i-1][u]]; for (int v:g[u]) { father[0][v]=u; dfs(v); T[u]=merge(T[u],T[v],1,m); } } int ed[maxn]; int main () { ios::sync_with_stdio(false); cin>>s; for (int i=0;i<s.size();i++) { sam_extend(s[i]); ed[i+1]=lst; } cin>>m; for (int i=1;i<=m;i++) { cin>>t[i]; lst=1; for (char ch:t[i]) sam_extend(ch),T[lst]=up(T[lst],1,m,i,1); } for (int i=2;i<=tot;i++) g[link[i]].push_back(i); dfs(1); cin>>q; while (q--) { int A,B,C,D; cin>>C>>D>>A>>B; int u=ed[B]; for (int i=20;i>=0;i--) { if (father[i][u]&&len[father[i][u]]>=B-A+1) { u=father[i][u]; } } pair<int,int> ans=query(T[u],1,m,C,D); if (ans.first==0) { ans={0,C}; } cout<<ans.second<<" "<<ans.first<<'\n'; } }