zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    FireFox 中 回把nextSibling为/n 换行时解释为undefinded
    陶哲轩实分析习题18.4.10
    单调可测集的测度运算
    数学分析_Tom Apostol_定理7.47
    Emacs+$\LaTeX$ 帮你写数学文章
    陶哲轩实分析引理18.4.2:半空间是可测集
    陶哲轩实分析习题18.4.10
    陶哲轩实分析引理18.4.2:半空间是可测集
    可测集的性质
    数学分析_Tom Apostol_定理7.47
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9475224.html
Copyright © 2011-2022 走看看