后缀数组

从 Trac 迁移的文章

这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。

原文章内容如下:

 == 倍增模板 == 
{{{
//要保证最后一个是0(其实只要最后一个和其他的不一样就行了)
//最后rank和sa数组都是1到n的
//n要记得自减
//别忘了更改str数组的类型
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn=200000+1;

int n;
char str[maxn];
int sa[maxn], rk[maxn];
int rs[maxn], ctn[maxn];
int height[maxn];

bool cmp0(int a, int b) { return str[a] < str[b]; }
int cmp(int a, int b, int l) { return rk[a] < rk[b] || rk[a+l] < rk[b+l]; }
void radix_sort(int l)
{
    int cnt = 0, i;
    for (i = n-1; i >= n-l; i--) ctn[cnt++] = i;
    for (i = 0; i < n; i++) if (sa[i] >= l) ctn[cnt++] = sa[i]-l;
    for (i = 0; i < n; i++) rs[i] = 0;
    for (i = 0; i < n; i++) rs[rk[i]]++;
    for (i = 1; i < n; i++) rs[i] += rs[i-1];
    for (i = n-1; i >= 0; i--) sa[--rs[rk[ctn[i]]]] = ctn[i];
    for (i = (ctn[*sa] = 0) + 1; i < n; i++)
        ctn[sa[i]] = cmp(sa[i-1], sa[i], l) + ctn[sa[i-1]];
    for (i = 0; i < n; i++) rk[i] = ctn[i];
}
void da()
{
    for (int i = 0; i < n; i++) sa[i] = i;
    sort(sa, sa+n, cmp0);
    for (int i = (rk[*sa] = 0) + 1; i < n; i++)
        rk[sa[i]] = cmp0(sa[i-1], sa[i]) + rk[sa[i-1]];
    for (int l = 1; rk[sa[n-1]] != n - 1; l <<= 1) radix_sort(l);
    for (int i = n-1; i >= 0; i--) rk[i] = rk[i-1], sa[i]++;
}
void make_height()
{
    int t = 0, p;
    for (int i = 1; i <= n; height[rk[i++]] = t)
        for (t?t--:0, p = sa[rk[i]-1]; str[i+t-1] == str[p+t-1]; t++) ;
}
}}}

 == 倍增模板(紧凑版) == 
{{{
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <ctime>
#define FORD(i,r,l) for(int i=(r);i>=(l);i--)
#define rep(i,n) for(int i=0;i<(n);i++)
#define req(i,l,n) for(int i=(l);i<(n);i++)
using namespace std;
const int maxn=100000+1;

int n;
char str[maxn];
int sa[maxn], *rk, initrk[maxn];
int rs[maxn], *ctn, initctn[maxn];
int height[maxn];

bool cmp0(int a, int b) { return str[a]<str[b]; }
int cmp(int a, int b, int l) { return rk[a]<rk[b]||rk[a+l]<rk[b+l]; }
void da()
{
    rk=initrk; ctn=initctn;
    rep (i,n) sa[i]=i;
    sort(sa,sa+n,cmp0);
    req (i,(rk[*sa]=0)+1,n)
        rk[sa[i]]=cmp0(sa[i-1],sa[i])+rk[sa[i-1]];
    for (int l=1,cnt;rk[sa[n-1]]!=n-1;l<<=1,swap(rk, ctn))
    {
        cnt=0;
        FORD (i,n-1,n-l) ctn[cnt++]=i;
        rep (i,n) if (sa[i]>=l) ctn[cnt++]=sa[i]-l;
        rep (i,n) rs[i]=0;
        rep (i,n) rs[rk[i]]++;
        req (i,1,n) rs[i]+=rs[i-1];
        FORD (i,n-1,0) sa[--rs[rk[ctn[i]]]]=ctn[i];
        req (i,(ctn[*sa]=0)+1,n)
            ctn[sa[i]]=cmp(sa[i-1],sa[i],l)+ctn[sa[i-1]];
    }
    FORD (i,n-1,0) rk[++sa[i]]=i;
}
void make_height()
{
    int t=0, p;
    for (int i=1;i<=n;height[rk[i++]]=t)
        for (t?t--:0,p=sa[rk[i]-1];str[i+t-1]==str[p+t-1];t++) ;
}
}}}

倍增模板

//要保证最后一个是0(其实只要最后一个和其他的不一样就行了)
//最后rank和sa数组都是1到n的
//n要记得自减
//别忘了更改str数组的类型
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn=200000+1;
int n;
char str[maxn];
int sa[maxn], rk[maxn];
int rs[maxn], ctn[maxn];
int height[maxn];
bool cmp0(int a, int b) { return str[a] < str[b]; }
int cmp(int a, int b, int l) { return rk[a] < rk[b] || rk[a+l] < rk[b+l]; }
void radix_sort(int l)
{
    int cnt = 0, i;
    for (i = n-1; i >= n-l; i--) ctn[cnt++] = i;
    for (i = 0; i < n; i++) if (sa[i] >= l) ctn[cnt++] = sa[i]-l;
    for (i = 0; i < n; i++) rs[i] = 0;
    for (i = 0; i < n; i++) rs[rk[i]]++;
    for (i = 1; i < n; i++) rs[i] += rs[i-1];
    for (i = n-1; i >= 0; i--) sa[--rs[rk[ctn[i]]]] = ctn[i];
    for (i = (ctn[*sa] = 0) + 1; i < n; i++)
        ctn[sa[i]] = cmp(sa[i-1], sa[i], l) + ctn[sa[i-1]];
    for (i = 0; i < n; i++) rk[i] = ctn[i];
}
void da()
{
    for (int i = 0; i < n; i++) sa[i] = i;
    sort(sa, sa+n, cmp0);
    for (int i = (rk[*sa] = 0) + 1; i < n; i++)
        rk[sa[i]] = cmp0(sa[i-1], sa[i]) + rk[sa[i-1]];
    for (int l = 1; rk[sa[n-1]] != n - 1; l <<= 1) radix_sort(l);
    for (int i = n-1; i >= 0; i--) rk[i] = rk[i-1], sa[i]++;
}
void make_height()
{
    int t = 0, p;
    for (int i = 1; i <= n; height[rk[i++]] = t)
        for (t?t--:0, p = sa[rk[i]-1]; str[i+t-1] == str[p+t-1]; t++) ;
}

倍增模板(紧凑版)

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <ctime>
#define FORD(i,r,l) for(int i=(r);i>=(l);i--)
#define rep(i,n) for(int i=0;i<(n);i++)
#define req(i,l,n) for(int i=(l);i<(n);i++)
using namespace std;
const int maxn=100000+1;
int n;
char str[maxn];
int sa[maxn], *rk, initrk[maxn];
int rs[maxn], *ctn, initctn[maxn];
int height[maxn];
bool cmp0(int a, int b) { return str[a]<str[b]; }
int cmp(int a, int b, int l) { return rk[a]<rk[b]||rk[a+l]<rk[b+l]; }
void da()
{
    rk=initrk; ctn=initctn;
    rep (i,n) sa[i]=i;
    sort(sa,sa+n,cmp0);
    req (i,(rk[*sa]=0)+1,n)
        rk[sa[i]]=cmp0(sa[i-1],sa[i])+rk[sa[i-1]];
    for (int l=1,cnt;rk[sa[n-1]]!=n-1;l<<=1,swap(rk, ctn))
    {
        cnt=0;
        FORD (i,n-1,n-l) ctn[cnt++]=i;
        rep (i,n) if (sa[i]>=l) ctn[cnt++]=sa[i]-l;
        rep (i,n) rs[i]=0;
        rep (i,n) rs[rk[i]]++;
        req (i,1,n) rs[i]+=rs[i-1];
        FORD (i,n-1,0) sa[--rs[rk[ctn[i]]]]=ctn[i];
        req (i,(ctn[*sa]=0)+1,n)
            ctn[sa[i]]=cmp(sa[i-1],sa[i],l)+ctn[sa[i-1]];
    }
    FORD (i,n-1,0) rk[++sa[i]]=i;
}
void make_height()
{
    int t=0, p;
    for (int i=1;i<=n;height[rk[i++]]=t)
        for (t?t--:0,p=sa[rk[i]-1];str[i+t-1]==str[p+t-1];t++) ;
}