zoukankan      html  css  js  c++  java
  • NOI 2018 你的名字 (后缀自动机+线段树合并)

    题目大意:略

    令$ION2017=S,ION2018=T$

    对$S$建$SAM$,每次都把$T$放进去跑,求出结尾是i的前缀串,能匹配上$S$的最长后缀长度为$f_{i}$

    由于$T$必须在$[l,r]$上匹配,设现在能匹配的长度为$len$,在后缀自动机的$x$点,添加一个字符$c$,则$trs[x][c]$的$right$集合中必须包含$endposin[l+len,r]$,这个操作可以用线段树合并实现

    否则$len$就要缩短,直到$len$缩短到$dep[pre_{x}]$,$len$如果再缩短就会无意义,跳$pre$,重复上述操作,直到$len$小于0

    求出$f_{i}$以后,我们还要对$T$去重,不去重就会爆零

    后缀自动机可以看成一个合并后缀的前缀树,相同的后缀是一定会被合并到一起的,每次都跳到能表示$T_{i-f_{i}+1,i}$的位置

    由于每次表示的串不一定能取满这个节点,所以答案是$sum_{2}^{tot} max(0,dep_{x}-max(dep_{pre_{x}},max(f_{k})))$

    仔细一想就能明白这个式子的含义了,考虑不合法的情况,要么$x$表示的串全都能被取,要么只能取到最大的经过它的$f_{i}$,取个补集即可

    $upd$:这道题卡$AK$的方式也很细节。

    我们把$T$放在$S$上匹配,求以每个位置为后缀,在$S$中的最长匹配长度$Len$时

    $Len$应该不断$-1$地缩减,直到缩减到$dep[fa]$,再跳到父节点$fa$,而不是直接缩减到$dep[fa]$

    因为我们用线段树合并去检验当前答案$len$是否合法,能取的区间是$[l+len,r]$

    如果$len$不合法,说明这个节点能表示的,长度为$len$的串不合法。

    如果这个节点还能表示其他长度小于$len$的串,就应该依次检查这些串是否都合法。

    代码体现就像我上面说的那样,$len$依次$-1$即可。

    时间复杂度依然不变,$len$依次$-1$,而我们从左往右遍历整个$T$串,类似于一个双指针,时间复杂度是$O(n)$级别,算上线段树合并就是$O(nlogn)$

      1 #include <cmath>
      2 #include <vector>
      3 #include <cstdio>
      4 #include <cstring>
      5 #include <algorithm>
      6 #define N1 500010
      7 #define S1 (N1<<1)
      8 #define ll long long
      9 #define uint unsigned int
     10 #define rint register int 
     11 #define dd double
     12 #define il inline 
     13 #define inf 0x3f3f3f3f
     14 #define idx(X) (X-'a')
     15 using namespace std;
     16 
     17 int gint()
     18 {
     19     int ret=0,fh=1;char c=getchar();
     20     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
     21     while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();}
     22     return ret*fh;
     23 }
     24 int n,len,cnt;
     25 /*struct Edge{
     26 int head[S1],to[S1],nxt[S1],cte;
     27 void ae(int u,int v){
     28     cte++;to[cte]=v,nxt[cte]=head[u],head[u]=cte;}
     29 }E;*/
     30 struct SEG{
     31 int sum[S1*60],ls[S1*60],rs[S1*60],root[S1],tot;
     32 int merge(int r1,int r2)
     33 {
     34     if(!r1||!r2) return r1+r2;
     35     int nx=++tot;
     36     sum[nx]=sum[r1]+sum[r2];
     37     ls[nx]=merge(ls[r1],ls[r2]);
     38     rs[nx]=merge(rs[r1],rs[r2]);
     39     return nx;
     40 }
     41 void update(int x,int l,int r,int &rt)
     42 {
     43     if(!rt) rt=++tot;
     44     sum[rt]++;
     45     if(l==r) return;
     46     int mid=(l+r)>>1;
     47     if(x<=mid) update(x,l,mid,ls[rt]);
     48     else update(x,mid+1,r,rs[rt]);
     49 }
     50 ll query(int L,int R,int l,int r,int rt)
     51 {
     52     if(!rt||L>R) return 0;
     53     if(L<=l&&r<=R) return sum[rt];
     54     int mid=(l+r)>>1;ll ans=0;
     55     if(L<=mid) ans+=query(L,R,l,mid,ls[rt]);
     56     if(R>mid) ans+=query(L,R,mid+1,r,rs[rt]);
     57     return ans;
     58 }
     59 }s;
     60 
     61 char str[S1];
     62 int L[S1];//sz[S1],psz[S1];
     63 namespace S{
     64 int trs[S1][26],pre[S1],dep[S1],la,tot;
     65 void init(){tot=la=1;}
     66 void insert(int c,int id)
     67 {
     68     int p=la,np=++tot,q,nq;la=np;
     69     dep[np]=dep[p]+1;
     70     for(;p&&!trs[p][c];p=pre[p]) trs[p][c]=np;
     71     s.update(id,1,n,s.root[np]);
     72     if(!p) {pre[np]=1;return;}
     73     q=trs[p][c];
     74     if(dep[q]==dep[p]+1) pre[np]=q;
     75     else{
     76         pre[nq=++tot]=pre[q];
     77         pre[q]=pre[np]=nq;
     78         dep[nq]=dep[p]+1;
     79         memcpy(trs[nq],trs[q],sizeof(trs[q]));
     80         for(;p&&trs[p][c]==q;p=pre[p]) trs[p][c]=nq;
     81     }
     82 }
     83 int hs[S1],que[S1];
     84 void topo()
     85 {
     86     int i,x;
     87     for(i=2;i<=tot;i++) hs[dep[i]]++;
     88     for(i=1;i<=tot;i++) hs[i]+=hs[i-1];
     89     for(i=2;i<=tot;i++) que[hs[dep[i]]--]=i;
     90     for(i=tot-1;i;i--)
     91     {
     92         x=que[i];
     93         s.root[pre[x]]=s.merge(s.root[x],s.root[pre[x]]);
     94     }
     95 }
     96 inline int Min(int X,int Y){return X<Y?X:Y;}
     97 void find(int l,int r)
     98 {
     99     int i,x=1,c,mi;
    100     for(i=1;i<=len;i++)
    101     {
    102         c=idx(str[i]);
    103         L[i]=L[i-1];
    104         while(1)
    105         {
    106             if(!trs[x][c]||!s.query(l+L[i],r,1,n,s.root[trs[x][c]])) {L[i]--;}
    107             else {L[i]++;x=trs[x][c];break;}
    108             if(L[i]==-1) {L[i]=0;break;}
    109             else if(L[i]==dep[pre[x]]) x=pre[x];
    110         } 
    111             /*for(;pre[x]&&(!trs[x][c]||!s.query(l+Min(L[i-1],dep[x]),r,1,n,s.root[trs[x][c]]));x=pre[x]);
    112             if(!trs[x][c]||){
    113                 L[i]=0;
    114             }else{
    115                 L[i]=min(L[i-1]+1,dep[x]+1);
    116                 x=trs[x][c];
    117             }*/
    118     }
    119 }
    120 };
    121 namespace T{
    122 int trs[S1][26],pre[S1],dep[S1],la,tot;
    123 void init(){tot=la=1;}
    124 void insert(int c)
    125 {
    126     int p=la,np=++tot,q,nq;la=np;
    127     dep[np]=dep[p]+1;
    128     for(;p&&!trs[p][c];p=pre[p]) trs[p][c]=np;
    129     if(!p) {pre[np]=1;return;}
    130     q=trs[p][c];
    131     if(dep[q]==dep[p]+1) pre[np]=q;
    132     else{
    133         pre[nq=++tot]=pre[q];
    134         pre[q]=pre[np]=nq;
    135         dep[nq]=dep[p]+1;
    136         memcpy(trs[nq],trs[q],sizeof(trs[q]));
    137         for(;p&&trs[p][c]==q;p=pre[p]) trs[p][c]=nq;
    138     }
    139 }
    140 int ma[S1],hs[S1],que[S1];
    141 ll uniq()
    142 {
    143     int i,x,c; ll ans=0;
    144     for(i=2;i<=tot;i++) hs[dep[i]]++;
    145     for(i=1;i<=tot;i++) hs[i]+=hs[i-1];
    146     for(i=2;i<=tot;i++) que[hs[dep[i]]--]=i;
    147     x=1;
    148     for(i=1;i<=len;i++)
    149     {
    150         c=idx(str[i]);
    151         for(;pre[x]&&dep[pre[x]]>=L[i]-1;x=pre[x]);
    152         x=trs[x][c];
    153         ma[x]=max(ma[x],L[i]);
    154     }
    155     for(i=tot-1;i;i--)
    156     {
    157         x=que[i];
    158         if(ma[x]) ma[pre[x]]=dep[pre[x]];
    159     }
    160     for(x=2;x<=tot;x++)
    161         ans+=max(0,dep[x]-max(dep[pre[x]],ma[x]));
    162     return ans;
    163 }
    164 void clr()
    165 {
    166     tot++;
    167     memset(hs,0,tot*4),memset(ma,0,tot*4);
    168     memset(que,0,tot*4),memset(pre,0,tot*4);
    169     memset(dep,0,tot*4),memset(trs,0,tot*4*26);
    170     memset(L,0,(len+1)*4);
    171     tot=la=1;
    172 }
    173 };
    174 
    175 int main()
    176 {
    177     freopen("t2.in","r",stdin);
    178     //freopen("a.out","w",stdout);
    179     int i,j,Q,l,r;ll ans1,ans2;
    180     S::init();
    181     scanf("%s",str+1);n=strlen(str+1);
    182     for(i=1;i<=n;i++) S::insert(idx(str[i]),i);
    183     S::topo();
    184     scanf("%d",&Q);
    185     for(i=1;i<=Q;i++)
    186     {
    187         scanf("%s",str+1);
    188         scanf("%d%d",&l,&r);
    189         len=strlen(str+1);
    190         T::clr();
    191         for(j=1;j<=len;j++) T::insert(idx(str[j]));
    192         S::find(l,r);
    193         printf("%lld
    ",T::uniq());
    194     }
    195     return 0;
    196 }
  • 相关阅读:
    weblogic 正常启动页面还是404
    oracle awr 生成
    jre 修改timezone 夏令时冬令时问题
    apache 2.4 配置loadbalance
    plsq 调试存储过程
    Windows怎么命令行修改文件权限
    Windows上面挂载NFS共享
    linux sar命令详解
    Tomcat Connector connectionTimeout含义和验证
    c++STL系列之Set
  • 原文地址:https://www.cnblogs.com/guapisolo/p/10137749.html
Copyright © 2011-2022 走看看