题意
给你一个串 $S$ 以及一个字符串数组 $T[1..m]$ , $q$ 次询问,每次问 $S$ 的子串 $S[p_l..p_r]$ 在 $T[l..r]$ 中的哪个串里的出现次数最多,并输出出现次数。如有多解输出最靠前的那一个。
题解
神仙题……虽然的确是好题……然而码量好大……好麻烦……因为一个sb错误调了一个下午
先膜一波zsy大佬……%%%
首先先把$T$给建出一个广义$SAM$。考虑每一个询问的$p_r$,如果在$SAM$上匹配到了一个节点,那么这个子串$S[p_l,p_r]$一定是这个节点的一个祖先(然后如果根本匹配不到的话直接跳过)
然后可以考虑倍增找到祖先,只要找到满足$len_u>=p_r-p_l+1$的最上面的节点就好了
然后考虑如何表示这个节点在$[l,r]$范围内在哪些串出现了多少次,以及出现次数的最大值。区间查询可以考虑用线段树。对于每一个$SAM$上的节点,我们对他建一棵线段树,表示有这个节点代表的字符串在$T$中的出现次数。然后通过倍增找到节点,在线段树上查询就是了
于是直接把串$S$放到$SAM$上跑,然后在每一个节点记录一下有哪些询问在这个点上,一波$dfs$的时候顺便合并父亲和儿子的出现次数的区间,并求出答案
说的好像很简单……然而真的码得有点想哭……
1 //minamoto 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 inline int read(){ 7 #define num ch-'0' 8 char ch;bool flag=0;int res; 9 while((ch=getchar())<'0'||ch>'9') 10 (ch=='-')&&(flag=true); 11 for(res=num;(ch=getchar())>='0'&&ch<='9';res=res*10+num); 12 (flag)&&(res=-res); 13 #undef num 14 return res; 15 } 16 char sr[1<<21],z[20];int C=-1,Z; 17 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;} 18 inline void print(int x,char ch){ 19 if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x; 20 while(z[++Z]=x%10+48,x/=10); 21 while(sr[++C]=z[Z],--Z);sr[++C]=ch; 22 } 23 const int N=5e5+5; 24 struct data{ 25 int x,y; 26 inline bool operator <(const data &b)const 27 {return x<b.x||x==b.x&&y>b.y;} 28 }ans[N]; 29 int L[N*20],R[N*20];data V[N*20]; 30 struct node{int l,r,pl,pr;}q[N]; 31 int n,m,Q,last=1,cnt=1,ch[N][26],fa[22][N],l[N],rt[N],tot=0; 32 int nxt[3][N],head[3][N]; 33 char s[N],t[N]; 34 void ins(int c){ 35 int p=last,np=++cnt;last=np,l[np]=l[p]+1; 36 for(;p&&!ch[p][c];p=fa[0][p]) ch[p][c]=np; 37 if(!p) fa[0][np]=1; 38 else{ 39 int q=ch[p][c]; 40 if(l[q]==l[p]+1) fa[0][np]=q; 41 else{ 42 int nq=++cnt;l[nq]=l[p]+1; 43 memcpy(ch[nq],ch[q],sizeof(ch[q])); 44 fa[0][nq]=fa[0][q],fa[0][q]=fa[0][np]=nq; 45 for(;ch[p][c]==q;p=fa[0][p]) ch[p][c]=nq; 46 } 47 } 48 } 49 void modify(int &now,int l,int r,int x){ 50 now=++tot; 51 if(l==r) return (void)(++V[now].x,V[now].y=l); 52 int mid=l+r>>1; 53 if(x<=mid) modify(L[now],l,mid,x); 54 else modify(R[now],mid+1,r,x); 55 V[now]=max(V[L[now]],V[R[now]]); 56 } 57 void merge(int &x,int y){ 58 if(!x||!y) return (void)(x|=y); 59 if(!L[x]&&!R[x]) return (void)(V[x].x+=V[y].x); 60 merge(L[x],L[y]),merge(R[x],R[y]); 61 V[x]=max(V[L[x]],V[R[x]]); 62 } 63 data query(int p,int l,int r,int ql,int qr){ 64 if(ql<=l&&qr>=r) return V[p]; 65 int mid=l+r>>1; 66 if(qr<=mid) return query(L[p],l,mid,ql,qr); 67 if(ql>mid) return query(R[p],mid+1,r,ql,qr); 68 return max(query(L[p],l,mid,ql,qr),query(R[p],mid+1,r,ql,qr)); 69 } 70 void dfs(int u){ 71 for(int i=head[0][u];i;i=nxt[0][i]) 72 dfs(i),merge(rt[u],rt[i]); 73 for(int i=head[2][u];i;i=nxt[2][i]) 74 ans[i]=query(rt[u],1,m,q[i].l,q[i].r); 75 } 76 int main(){ 77 scanf("%s",s+1);n=strlen(s+1); 78 m=read(); 79 for(int i=1;i<=m;++i){ 80 scanf("%s",t+1);int len=strlen(t+1);last=1; 81 for(int j=1;j<=len;++j) ins(t[j]-'a'),modify(rt[last],1,m,i); 82 } 83 Q=read(); 84 for(int i=1;i<=Q;++i){ 85 int a=read(),b=read(),c=read(),d=read(); 86 q[i]=(node){a,b,c,d}; 87 nxt[1][i]=head[1][q[i].pr],head[1][q[i].pr]=i; 88 } 89 for(int i=2;i<=cnt;++i) 90 nxt[0][i]=head[0][fa[0][i]],head[0][fa[0][i]]=i; 91 for(int j=1;j<22;++j) 92 for(int i=2;i<=cnt;++i) 93 fa[j][i]=fa[j-1][fa[j-1][i]]; 94 for(int i=1,now=1,cnt=0;i<=n;++i){ 95 while(now&&!ch[now][s[i]-'a']) now=fa[0][now],cnt=l[now]; 96 if(!now){now=1,cnt=0;continue;} 97 now=ch[now][s[i]-'a'],++cnt; 98 for(int j=head[1][i];j;j=nxt[1][j]){ 99 int u=now;if(cnt<q[j].pr-q[j].pl+1) continue; 100 for(int k=21;~k;--k) 101 if(l[fa[k][u]]>=q[j].pr-q[j].pl+1) 102 u=fa[k][u]; 103 nxt[2][j]=head[2][u],head[2][u]=j; 104 } 105 } 106 dfs(1); 107 for(int i=1;i<=Q;++i){ 108 if(!ans[i].x) ans[i].y=q[i].l; 109 print(ans[i].y,32),print(ans[i].x,10); 110 } 111 Ot(); 112 return 0; 113 }