CF666E Forensic Examination(后缀自动机+动态线段树)

题意

  给你一个串 $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 }
原文地址:https://www.cnblogs.com/bztMinamoto/p/9475224.html