后缀数组

先写一个在线的多模字符串匹配

O(m+logn)的,按照https://wenku.baidu.com/view/cd7db304e87101f69e31953e.html的思想,很难写

没地方交啊

只能找出是否出现,不能找出出现了几次

要找出现的次数,大概就是二分第一个出现的位置和最后一个出现的位置吧?不确定能不能写

拍了一会没出错,先当做对的好了

  1 #include<iostream>
  2 #include<algorithm>
  3 #include<string>
  4 using namespace std;
  5 string str[1000100],txt;
  6 int n;
  7 namespace SA
  8 {
  9     int n,p,m=128,sa[1000100],t1[1000100],t2[1000100],cnt[1000100],*x=t1,*y=t2;
 10     int *height=t2,*rk=t1;
 11     int st[1000100][21],log2x[1000100],lft[21];
 12     const int log2n=20;
 13     void build()
 14     {
 15         int i,k;
 16         n=txt.length();
 17         for(i=0;i<n;i++)    cnt[x[i]=txt[i]]++;
 18         for(i=1;i<m;i++)    cnt[i]+=cnt[i-1];
 19         for(i=n-1;i>=0;i--)    sa[--cnt[x[i]]]=i;
 20         for(k=1;k<=n;k<<=1)
 21         {
 22             p=0;
 23             for(i=n-k;i<n;i++)    y[p++]=i;
 24             for(i=0;i<n;i++)    if(sa[i]>=k)    y[p++]=sa[i]-k;
 25             for(i=0;i<m;i++)    cnt[i]=0;
 26             for(i=0;i<n;i++)    cnt[x[y[i]]]++;
 27             for(i=1;i<m;i++)    cnt[i]+=cnt[i-1];
 28             for(i=n-1;i>=0;i--)    sa[--cnt[x[y[i]]]]=y[i];
 29             swap(x,y);p=0;
 30             x[sa[0]]=0;
 31             for(i=1;i<n;i++)
 32                 x[sa[i]]=y[sa[i]]==y[sa[i-1]]
 33                 &&(sa[i]+k<n?y[sa[i]+k]:0)==(sa[i-1]+k<n?y[sa[i-1]+k]:0)
 34                 ?p:++p;
 35             if(p>=n)    break;
 36             m=p+1;
 37         }
 38         for(i=0;i<n;i++)    rk[sa[i]]=i;
 39         for(i=0,k=0;i<n;i++)
 40         {
 41             if(k)    k--;
 42             if(rk[i])
 43                 while(sa[rk[i]-1]+k<n&&i+k<n&&txt[sa[rk[i]-1]+k]==txt[i+k])    k++;
 44             height[rk[i]]=k;
 45         }
 46         lft[0]=1;for(i=1;i<=log2n;i++)    lft[i]=lft[i-1]<<1;
 47         log2x[1]=k=0;
 48         for(i=2;i<=1000000;i++)
 49         {
 50             if(i>=lft[k+1])    ++k;
 51             log2x[i]=k;
 52         }
 53         for(i=0;i<n;i++)    st[i][0]=height[i];
 54         for(k=1;k<=log2n;k++)
 55             for(i=0;i<n-lft[k]+1;i++)
 56                 st[i][k]=min(st[i][k-1],st[i+lft[k-1]][k-1]);
 57     }
 58     int lcp(int l,int r)
 59     {
 60         if(l==r)    return n-l;
 61         l=rk[l];r=rk[r];if(l>r) swap(l,r);
 62         l++;int k=log2x[r-l+1];
 63         return min(st[l][k],st[r-lft[k]+1][k]);
 64     }
 65     int lcp(const char *x,int l)
 66     {
 67         int ans=0;
 68         while(*x&&l<n&&*x==txt[l])    ++x,++l,++ans;
 69         return ans;
 70     }
 71     bool find(const string &x)
 72     {
 73         int l=0,r=n-1,t,mid,mmatch=lcp(x.c_str(),0),mpos=0,m=x.length(),state;
 74         while(r>l)
 75         {
 76             mid=(l+r)/2;t=lcp(sa[mid],mpos);
 77             if(t<mmatch)
 78             {
 79                 if(x[t]<txt[sa[mid]+t])    state=-1;
 80                 //else if(x[t]==txt[sa[mid]+t])    state=0;
 81                 else state=1;
 82             }
 83             else
 84             {
 85                 mpos=sa[mid];
 86                 while(mmatch<m&&mmatch+mpos<n&&x[mmatch]==txt[mmatch+mpos])    mmatch++;
 87                 if(mmatch==m)    state=0;
 88                 else if(x[mmatch]<txt[mmatch+mpos])    state=-1;
 89                 else if(x[mmatch]>txt[mmatch+mpos])    state=1;
 90             }
 91             if(state<0)    r=mid-1;
 92             else if(state==0)    return 1;
 93             else l=mid+1;
 94         }
 95         return lcp(x.c_str(),sa[l])==m;
 96     }
 97 }
 98 int ans;
 99 int main()
100 {
101     int i;
102     cin>>n;
103     for(i=1;i<=n;i++)    cin>>str[i];
104     cin>>txt;
105     SA::build();
106     //for(i=0;i<SA::n;i++)    cout<<SA::sa[i]+1<<' ';
107     for(i=1;i<=n;i++)    ans+=SA::find(str[i]);
108     cout<<ans;
109     return 0;
110 }

另一份后缀数组模板

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 using namespace std;
 5 char s[1000100];
 6 int n;
 7 int sa[1000100],t1[1000100],t2[1000100],cnt[1000100];
 8 int *x=t1,*y=t2,m='z',p;
 9 int main()
10 {
11     int i,k;
12     scanf("%s",s+1);n=strlen(s+1);
13     for(i=1;i<=n;i++)    cnt[x[i]=s[i]]++;
14     for(i=1;i<=m;i++)    cnt[i]+=cnt[i-1];
15     for(i=n;i>=1;i--)    sa[cnt[x[i]]--]=i;
16     for(k=1;k<=n;k<<=1)
17     {
18         //x[i]存上一轮中后缀i的rank
19         p=0;
20         for(i=n-k+1;i<=n;i++)    y[++p]=i;
21         for(i=1;i<=n;i++)    if(sa[i]>k)    y[++p]=sa[i]-k;
22         //y[i]暂存对第二关键字排序后的rank为i的后缀编号
23         for(i=1;i<=m;i++)    cnt[i]=0;
24         for(i=1;i<=n;i++)    cnt[x[y[i]]]++;
25         for(i=1;i<=m;i++)    cnt[i]+=cnt[i-1];
26         for(i=n;i>=1;i--)    sa[cnt[x[y[i]]]--]=y[i];
27         
28         swap(x,y);p=0;
29         for(i=1;i<=n;i++)    x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?p:++p;
30         if(p>=n)    break;
31         m=p;
32     }
33     for(i=1;i<=n;i++)    printf("%d ",sa[i]);
34     return 0;
35 }

nlog^2n构造简单代码

inline bool cmp(int u,int v)
{
    if(rank[u]!=rank[v]) return rank[u]<rank[v];
    int nu,nv;
    nu= (u+l>len?0:rank[u+l]);
    nv= (v+l>len?0:rank[v+l]);
    return nu<nv;
}
 
int main()
{
    int i,j,k;
    scanf("%s",str+1);
    len=strlen(str+1);
    for(i=1; i<=len; i++)
    {
        rank[i]=str[i];
        st[i]=i;
    }
    for(l=1; l<=len; l<<=1)
    {
        sort(st+1,st+len+1,cmp);
        tmp[st[1]]=1;
        for(i=2; i<=len; i++)
        {
            tmp[st[i]]=tmp[st[i-1]]+cmp(st[i-1],st[i]);
        }
        for(i=1; i<=len; i++)
        {
            rank[i]=tmp[i];
        }
    }
}
原文地址:https://www.cnblogs.com/hehe54321/p/8658036.html