Codeforces 666E Forensic Examination
题意:给定主串s和m个模式串,每次询问[l,r]的模式串中出现s[pl...pr]次数最多的串和次数。
这题挺简单的,先把所有模式串拿来建广义后缀自动机,询问相当于子树众数,用线段树合并即可。
那我为什么写这题题解呢?
1.作为我博客第一道非BZOJ题。
2.作为我博客第一道写题意(英文)的题。
3.这题是老师留的作业,所以可以骗访问量。
4.记录一下广义后缀自动机的优秀写法,以前我是无脑建的。
#include <cstdio> #include <algorithm> using namespace std; #define l(x) t[x].l #define r(x) t[x].r #define M ((L+R)>>1) typedef pair<int,int> pr; const int S=500005,N=100005; char s[N],sr[S]; int m,e,q,l1,r1,l2,r2,ls,sz,tt,po[S],ln[S],l[N],f[N],ch[N][26],hd[N],nx[N],to[N],rt[N],fa[N][21]; struct nd {int l,r; pr p;}t[N*30]; void ad(int x,int y) {to[++e]=y,nx[e]=hd[x],hd[x]=e;} void ins(int c) { int u=ls,x=ch[u][c]; if(x) { if(l[u]+1==l[x]) {ls=x; return;} l[++sz]=l[u]+1,f[sz]=f[x],f[x]=sz,ls=sz; for(int j=0;j<26;j++) ch[sz][j]=ch[x][j]; for(;u&&ch[u][c]==x;u=f[u]) ch[u][c]=sz; if(ch[u][c]==x) ch[u][c]=sz; } else { for(ls=++sz,l[sz]=l[u]+1;u&&!ch[u][c];u=f[u]) ch[u][c]=sz; int x=ch[u][c]; if(!x) {ch[u][c]=sz; return;} if(l[u]+1==l[x]) {f[sz]=x; return;} l[++sz]=l[u]+1,f[sz]=f[x],f[x]=f[ls]=sz; for(int j=0;j<26;j++) ch[sz][j]=ch[x][j]; for(;u&&ch[u][c]==x;u=f[u]) ch[u][c]=sz; if(ch[u][c]==x) ch[u][c]=sz; } } void pu(int x) {t[x].p=max(t[l(x)].p,t[r(x)].p);} int mrg(int x,int y,int L=1,int R=m) { if(!x||!y) return x|y; int z=++tt; if(L==R) {t[z].p=make_pair(t[x].p.first+t[y].p.first,-L); return z;} l(z)=mrg(l(x),l(y),L,M),r(z)=mrg(r(x),r(y),M+1,R),pu(z); return z; } void upd(int &x,int v,int L=1,int R=m) { if(!x) x=++tt; if(L==R) {t[x].p=make_pair(t[x].p.first+1,-v); return;} if(v<=M) upd(l(x),v,L,M); else upd(r(x),v,M+1,R); pu(x); } pr qr(int x,int l,int r,int L=1,int R=m) { if(!x) return make_pair(0,0); if(l<=L&&r>=R) return t[x].p; if(r<=M) return qr(l(x),l,r,L,M); if(l>M) return qr(r(x),l,r,M+1,R); return max(qr(l(x),l,r,L,M),qr(r(x),l,r,M+1,R)); } int gt(int x,int ln) {for(int i=20;~i;i--) if(l[fa[x][i]]>=ln) x=fa[x][i]; return x;} void dfs(int x) {for(int i=hd[x];i;i=nx[i]) dfs(to[i]),rt[x]=mrg(rt[x],rt[to[i]]),fa[to[i]][0]=x;} int main() { scanf("%s%d",sr,&m); for(int i=1;i<=m;i++) { scanf("%s",s),ls=0; for(int j=0;s[j];j++) ins(s[j]-'a'),upd(rt[ls],i); } for(int i=0,u=0,s=0;sr[i];i++) { int c=sr[i]-'a'; while(u&&!ch[u][c]) u=f[u],s=l[u]; if(ch[u][c]) ln[i+1]=++s,u=ch[u][c],po[i+1]=u; } for(int i=1;i<=sz;i++) ad(f[i],i); dfs(0),scanf("%d",&q); for(int j=1;j<21;j++) for(int i=1;i<=sz;i++) fa[i][j]=fa[fa[i][j-1]][j-1]; while(q--) { scanf("%d%d%d%d",&l1,&r1,&l2,&r2); if(ln[r2]<r2-l2+1) {printf("%d 0\n",l1); continue;} pr k=qr(rt[gt(po[r2],r2-l2+1)],l1,r1); if(k.first) printf("%d %d\n",-k.second,k.first); else printf("%d 0\n",l1); } return 0; }