CodeForces666E Forensic Examination
题目描述
给你一个串S以及一个字符串数组T[1..m],q次询问,每次问S的子串S[pl..pr]在T[l..r]中的哪个串里的出现次数最多,并输出出现次数。
如有多解输出最靠前的那一个。
题解
算是道字符串比较套路的题吧。
对模式串建SAM,对所有模式串的所有前缀维护right集合。
然后对于每个询问,倍增找到关键点,查子树众数。
坑:在最匹配串做匹配的时候,要记录匹配长度,如果匹配长度不够询问长度,直接判无解。
代码
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #define N 1000009 using namespace std; typedef long long ll; int ch[N][26],tott,tr[N*32],id[N*32],ls[N*32],rs[N*32],ans1,ans2,fa[N],mat[N]; int cnt,last,l[N],tot,head[N],n,p[21][N],deep[N],T[N],tag[N]; char s[N],s1[N]; inline int rd(){ int x=0;char c=getchar();bool f=0; while(!isdigit(c)){if(c=='-')f=1;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();} return f?-x:x; } void upd(int &cnt,int l,int r,int x){ if(!cnt)cnt=++tott; if(l==r){tr[cnt]++;id[cnt]=l;return;} int mid=(l+r)>>1; if(mid>=x)upd(ls[cnt],l,mid,x); else upd(rs[cnt],mid+1,r,x); tr[cnt]=max(tr[ls[cnt]],tr[rs[cnt]]); id[cnt]=tr[ls[cnt]]>=tr[rs[cnt]]?id[ls[cnt]]:id[rs[cnt]]; } int merge(int x,int y,int l,int r){ if(!x||!y)return x^y; int p=++tott; if(l==r){tr[p]=tr[x]+tr[y];id[p]=l;return p;} int mid=(l+r)>>1; ls[p]=merge(ls[x],ls[y],l,mid);rs[p]=merge(rs[x],rs[y],mid+1,r); tr[p]=max(tr[ls[p]],tr[rs[p]]); id[p]=tr[ls[p]]>=tr[rs[p]]?id[ls[p]]:id[rs[p]]; return p; } void query(int cnt,int l,int r,int L,int R){ if(!cnt)return; if(l>=L&&r<=R){ if(tr[cnt]>ans1){ ans1=tr[cnt]; ans2=id[cnt]; } return; } int mid=(l+r)>>1; if(mid>=L)query(ls[cnt],l,mid,L,R); if(mid<R)query(rs[cnt],mid+1,r,L,R); } inline void ins(int x,int id){ if(ch[last][x]){ int p=last,q=ch[last][x]; if(l[p]+1==l[q])last=q; else{ int nq=++cnt;l[nq]=l[p]+1; memcpy(ch[nq],ch[q],sizeof(ch[nq])); fa[nq]=fa[q];fa[q]=nq; for(;ch[p][x]==q;p=fa[p])ch[p][x]=nq; last=nq; } } else{ int p=last,np=++cnt;l[np]=l[p]+1;last=np; for(;p&&!ch[p][x];p=fa[p])ch[p][x]=np; if(!p)fa[np]=1; else{ int q=ch[p][x]; if(l[p]+1==l[q])fa[np]=q; else{ int nq=++cnt;l[nq]=l[p]+1; memcpy(ch[nq],ch[q],sizeof(ch[nq])); fa[nq]=fa[q];fa[q]=fa[np]=nq; for(;ch[p][x]==q;p=fa[p])ch[p][x]=nq; } } } upd(T[last],1,n,id); } struct edge{int n,to;}e[N]; inline void add(int u,int v){e[++tot].n=head[u];e[tot].to=v;head[u]=tot;} void dfs(int u){ for(int i=1;(1<<i)<=deep[u];++i)p[i][u]=p[i-1][p[i-1][u]]; for(int i=head[u];i;i=e[i].n){ int v=e[i].to;deep[v]=deep[u]+1;p[0][v]=u; dfs(v);T[u]=merge(T[u],T[v],1,n); } } int main(){ scanf("%s",s+1); n=rd();cnt=1; for(int i=1;i<=n;++i){ last=1; scanf("%s",s1);int len=strlen(s1); for(int j=0;j<len;++j)ins(s1[j]-'a',i); } for(int i=1;i<=cnt;++i)if(fa[i])add(fa[i],i); dfs(1);int len=strlen(s+1),now=1,le=0; for(int i=1;i<=len;++i){ while(now&&!ch[now][s[i]-'a'])now=fa[now],le=l[now]; if(!now)now=1; if(ch[now][s[i]-'a'])now=ch[now][s[i]-'a'],le++; tag[i]=now;mat[i]=le; } int q=rd(),l1,r1,l2,r2; while(q--){ l2=rd();r2=rd();l1=rd();r1=rd(); int x=tag[r1]; if(!x||mat[r1]<r1-l1+1){ printf("%d 0\n",l2);continue; } for(int i=20;i>=0;--i)if(l[p[i][x]]>=r1-l1+1)x=p[i][x]; ans1=0;ans2=l2;; query(T[x],1,n,l2,r2); printf("%d %d\n",ans2,ans1); } return 0; }