zoukankan      html  css  js  c++  java
  • CF666E Forensic Examination SAM+倍增,线段树和并

    题面:

      给你一个串S以及一个字符串数组T[1..m],q次询问,每次问S的子串S[p_l..p_r]在T[l..r]中的哪个串里的出现次数最多,并输出出现次数。如有多解输出最靠前的那一个。

    分析:

      第一次见这道题时,由于对算法十分陌生,就将其压进了任务计划,这一天又提到了这道题,这才算是重见天日。

      数据结构题,越来越注重多种数据结构的搭配使用。搭配使用呢,我们就要知道各种数据结构的功能与适用范围,下面是这道题一个理想的思考过程(虽然我是抄的题解……)

      首先,一个模式串的区间要在多个串上进行匹配,我们可以想到多串构造的广义后缀自动机。

      由于我们要对一个模式串的区间,询问:在一个区间的匹配串中,最多出现在哪个匹配串,以及出现了多少次。(有点拗口)

      我们需要使用一个支持区间查询的数据结构,并且,我们需要支持在SAM上,查询一个点的right集合中的所有点的信息。

      我们采取的策略是,对于SAM的每一个点,我们建一棵值域为1~m的权值线段树,然后离线处理询问,将询问挂链(开vector存下来应该也可以),然后自底向上线段树合并,回答询问。

      但是,我们对询问应该怎样调整一下呢,总不能对于每个区间都在广义SAM上跑一遍吧~

      我们要总地把模式串S在SAM上跑一遍,只需要对每个询问记录右端点qr,当S匹配到这个点的时候,将所有右端点为qr的询问挂到链上,(为什么不直接挂链呢,因为我们不能随便挂链,需要挂到SAM上最早包含模式串这一段的那个点上(也就是匹配到当前点时,parent树上最远的一个len大于这一段长度的点上)),这里言语很难解释,只有自己体会这样做的妙处。但是这步操作怎么做呢,暴跳的话理论复杂度是过不去的(但实际上过得去),所以我们最好用一个倍增数组来做这个。(万一被hack掉可就不好了)

      然后这道题跑线段树合并即可,由于是抄的题解代码,所以代码风格不太对(除了压行风格)请理智吸收。

    代码:

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 const int N=1000005;
      4 struct SAM{
      5     struct node{
      6         int son[26],fa,l;
      7     }t[N];int lst,cnt;
      8     void init(){lst=cnt=1;}
      9     void ins(int c){
     10         int p=lst,np=++cnt;lst=np;
     11         t[np].l=t[p].l+1;
     12         for(;p&&!t[p].son[c];p=t[p].fa) 
     13         t[p].son[c]=np;if(!p) t[np].fa=1;
     14         else{
     15             int q=t[p].son[c];
     16             if(t[q].l==t[p].l+1) t[np].fa=q;
     17             else{
     18                 int nq=++cnt;t[nq]=t[q];
     19                 t[nq].l=t[p].l+1;
     20                 t[q].fa=t[np].fa=nq;
     21                 while(p&&t[p].son[c]==q)
     22                 t[p].son[c]=nq,p=t[p].fa;
     23             }
     24         }
     25     }
     26 }sam;int n,m,f[N][22];
     27 struct data{int v,p;}ans[N];
     28 bool operator<(data a,data b){
     29     return (a.v<b.v)||(a.v==b.v&&a.p>b.p);
     30 } struct segtree{int ls,rs;data v;}t[N<<4];
     31 struct que{int l,r,pl,pr;}q[N];
     32 int tot,rt[N];char S[N],T[N];
     33 void update(int &x,int l,int r,int p){
     34     if(!x) x=++tot;if(l==r)
     35     {t[x].v.v++;t[x].v.p=p;return;}
     36     int mid=l+r>>1;
     37     if(p<=mid) update(t[x].ls,l,mid,p);
     38     else update(t[x].rs,mid+1,r,p);
     39     t[x].v=max(t[t[x].ls].v,t[t[x].rs].v);
     40 } int merge(int x,int y){
     41     if(!y||!x) return x|y;
     42     if(!t[x].ls&&!t[x].rs)
     43     {t[x].v.v+=t[y].v.v;return x;}
     44     t[x].ls=merge(t[x].ls,t[y].ls);
     45     t[x].rs=merge(t[x].rs,t[y].rs);
     46     t[x].v=max(t[t[x].ls].v,t[t[x].rs].v);
     47     return x;
     48 } data query(int x,int l,int r,int L,int R){
     49     if(L<=l&&r<=R) return t[x].v;
     50     int mid=l+r>>1;if(R<=mid)
     51     return query(t[x].ls,l,mid,L,R);
     52     if(L>mid) return query(t[x].rs,mid+1,r,L,R);
     53     return max(query(t[x].ls,l,mid,L,R),
     54     query(t[x].rs,mid+1,r,L,R));
     55 } struct link{
     56     struct line{int y,nxt;}e[N];
     57     int h[N],c;void add(int x,int y)
     58     {e[++c]=(line){y,h[x]};h[x]=c;}
     59 }par,qy,aw;void dfs(int x){
     60     for(int i=par.h[x];i;i=par.e[i].nxt)
     61     dfs(par.e[i].y),rt[x]=merge(rt[x],rt[par.e[i].y]);
     62     for(int i=aw.h[x];i;i=aw.e[i].nxt)
     63     ans[aw.e[i].y]=query(rt[x],1,m,q[aw.e[i].y].l,
     64     q[aw.e[i].y].r);return ;
     65 } int main(){
     66     scanf("%s",S+1);n=strlen(S+1);
     67     scanf("%d",&m);sam.init();
     68     for(int i=1;i<=m;i++){
     69         sam.lst=1;scanf("%s",T+1);
     70         for(int j=1,l=strlen(T+1);j<=l;j++)
     71         sam.ins(T[j]-97),update(rt[sam.lst],1,m,i);
     72     } int Q;scanf("%d",&Q);
     73     for(int i=1,l,r,pl,pr;i<=Q;i++){
     74         scanf("%d%d%d%d",&l,&r,&pl,&pr);
     75         q[i]=(que){l,r,pl,pr};qy.add(q[i].pr,i);
     76     } for(int i=2;i<=sam.cnt;i++)
     77     par.add(f[i][0]=sam.t[i].fa,i);
     78     for(int i=1;i<22;i++)
     79     for(int j=1;j<=sam.cnt;j++)
     80     f[j][i]=f[f[j][i-1]][i-1];
     81     for(int i=1,nw=1,len=0;i<=n;i++){
     82         int c=S[i]-97;
     83         while(nw&&!sam.t[nw].son[c])
     84         nw=sam.t[nw].fa,len=sam.t[nw].l;
     85         if(!nw){nw=1,len=0;continue;}
     86         nw=sam.t[nw].son[c];len+=1;
     87         for(int j=qy.h[i];j;j=qy.e[j].nxt){
     88             int y=qy.e[j].y,x=nw,tmp;
     89             tmp=q[y].pr-q[y].pl+1;
     90             if(len<tmp) continue;
     91             for(int k=21;~k;k--)
     92             if(sam.t[f[x][k]].l>=tmp) x=f[x][k];
     93             aw.add(x,y);
     94         }
     95     } dfs(1);
     96     for(int i=1;i<=Q;i++){
     97         if(!ans[i].v) ans[i].p=q[i].l;
     98         printf("%d %d
    ",ans[i].p,ans[i].v);
     99     } return 0;
    100 }
    理论上过得去但跑的慢
     1 //这是CF666E理论上过不去(但实际上过得去)的代码 
     2 #include<bits/stdc++.h>
     3 using namespace std;
     4 const int N=1000005;
     5 struct SAM{
     6     struct node{
     7         int son[26],fa,l;
     8     }t[N];int lst,cnt;
     9     void init(){lst=cnt=1;}
    10     void ins(int c){
    11         int p=lst,np=++cnt;lst=np;
    12         t[np].l=t[p].l+1;
    13         for(;p&&!t[p].son[c];p=t[p].fa) 
    14         t[p].son[c]=np;if(!p) t[np].fa=1;
    15         else{
    16             int q=t[p].son[c];
    17             if(t[q].l==t[p].l+1) t[np].fa=q;
    18             else{
    19                 int nq=++cnt;t[nq]=t[q];
    20                 t[nq].l=t[p].l+1;
    21                 t[q].fa=t[np].fa=nq;
    22                 while(p&&t[p].son[c]==q)
    23                 t[p].son[c]=nq,p=t[p].fa;
    24             }
    25         }
    26     }
    27 }sam;int n,m,f[N][22];
    28 struct data{int v,p;}ans[N];
    29 bool operator<(data a,data b){
    30     return (a.v<b.v)||(a.v==b.v&&a.p>b.p);
    31 } struct segtree{int ls,rs;data v;}t[N<<4];
    32 struct que{int l,r,pl,pr;}q[N];
    33 int tot,rt[N];char S[N],T[N];
    34 void update(int &x,int l,int r,int p){
    35     if(!x) x=++tot;if(l==r)
    36     {t[x].v.v++;t[x].v.p=p;return;}
    37     int mid=l+r>>1;
    38     if(p<=mid) update(t[x].ls,l,mid,p);
    39     else update(t[x].rs,mid+1,r,p);
    40     t[x].v=max(t[t[x].ls].v,t[t[x].rs].v);
    41 } int merge(int x,int y){
    42     if(!y||!x) return x|y;
    43     if(!t[x].ls&&!t[x].rs)
    44     {t[x].v.v+=t[y].v.v;return x;}
    45     t[x].ls=merge(t[x].ls,t[y].ls);
    46     t[x].rs=merge(t[x].rs,t[y].rs);
    47     t[x].v=max(t[t[x].ls].v,t[t[x].rs].v);
    48     return x;
    49 } data query(int x,int l,int r,int L,int R){
    50     if(L<=l&&r<=R) return t[x].v;
    51     int mid=l+r>>1;if(R<=mid)
    52     return query(t[x].ls,l,mid,L,R);
    53     if(L>mid) return query(t[x].rs,mid+1,r,L,R);
    54     return max(query(t[x].ls,l,mid,L,R),
    55     query(t[x].rs,mid+1,r,L,R));
    56 } struct link{
    57     struct line{int y,nxt;}e[N];
    58     int h[N],c;void add(int x,int y)
    59     {e[++c]=(line){y,h[x]};h[x]=c;}
    60 }par,qy,aw;void dfs(int x){
    61     for(int i=par.h[x];i;i=par.e[i].nxt)
    62     dfs(par.e[i].y),rt[x]=merge(rt[x],rt[par.e[i].y]);
    63     for(int i=aw.h[x];i;i=aw.e[i].nxt)
    64     ans[aw.e[i].y]=query(rt[x],1,m,q[aw.e[i].y].l,
    65     q[aw.e[i].y].r);return ;
    66 } int main(){
    67     scanf("%s",S+1);n=strlen(S+1);
    68     scanf("%d",&m);sam.init();
    69     for(int i=1;i<=m;i++){
    70         sam.lst=1;scanf("%s",T+1);
    71         for(int j=1,l=strlen(T+1);j<=l;j++)
    72         sam.ins(T[j]-97),update(rt[sam.lst],1,m,i);
    73     } int Q;scanf("%d",&Q);
    74     for(int i=1,l,r,pl,pr;i<=Q;i++){
    75         scanf("%d%d%d%d",&l,&r,&pl,&pr);
    76         q[i]=(que){l,r,pl,pr};qy.add(q[i].pr,i);
    77     } for(int i=2;i<=sam.cnt;i++)
    78     par.add(f[i][0]=sam.t[i].fa,i);
    79     for(int i=1,nw=1,len=0;i<=n;i++){
    80         int c=S[i]-97;
    81         while(nw&&!sam.t[nw].son[c])
    82         nw=sam.t[nw].fa,len=sam.t[nw].l;
    83         if(!nw){nw=1,len=0;continue;}
    84         nw=sam.t[nw].son[c];len+=1;
    85         for(int j=qy.h[i];j;j=qy.e[j].nxt){
    86             int y=qy.e[j].y,x=nw,tmp;
    87             tmp=q[y].pr-q[y].pl+1;
    88             if(len<tmp) continue;
    89             while(sam.t[f[x][0]].l>=tmp) x=f[x][0];
    90             aw.add(x,y);
    91         }
    92     } dfs(1);
    93     for(int i=1;i<=Q;i++){
    94         if(!ans[i].v) ans[i].p=q[i].l;
    95         printf("%d %d
    ",ans[i].p,ans[i].v);
    96     } return 0;
    97 }
    理论上过不去但跑得更快
  • 相关阅读:
    网页版游戏(俄罗斯方块)
    模拟简单进程调度实验
    从小型网站到超大规模网站的MySQL参考架构
    Google Chart Tools学习笔记 二 Area Chart
    大话设计模式——建造者模式
    内存管理:分页,分段,段页结合
    2012第50周星期一自制力网摘
    第49周星期五糟糕破系统
    2012年第50周四
    2012第50周五
  • 原文地址:https://www.cnblogs.com/Alan-Luo/p/10421585.html
Copyright © 2011-2022 走看看