后缀数组 dc3 模板

  1. SA 按顺序排列。
  2. ranks指出了每一个位置的排名。
//maxn 表示后缀的个数
#define maxn 200010
#define F(x) ((x)/3+((x)%3==1?0:tb))
#define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)

int Ra[maxn], Rb[maxn], Rv[maxn], Rs[maxn];
int c0(int r[], int a, int b){
    return r[a]==r[b] && r[a+1]==r[b+1] && r[a+2]==r[b+2];
}
int c12(int k, int r[], int a, int b){
    if(k==2)
        return r[a]<r[b] || (r[a]==r[b] && c12(1,r,a+1,b+1));
    else
        return r[a]<r[b] || (r[a]==r[b] && Rv[a+1]<Rv[b+1]);
}

//r保存数据,a保存待排序字符下标,b保存3长度字符串的首字符下标,m表示基数的容量
void Rsort(int r[], int a[], int b[], int n, int m){
    int i;
    for(i = 0; i < n; ++i)  Rv[i] = r[a[i]];//Rv表示待排序字符
    for(i = 0; i < m; ++i)  Rs[i] = 0;//初始化桶
    for(i = 0; i < n; ++i)  ++Rs[Rv[i]];//对应桶自增
    for(i = 1; i < m; ++i)  Rs[i] += Rs[i-1];//使每一个桶都能反映出排名
    for(i = n-1; i >= 0; --i)  b[--Rs[Rv[i]]] = a[i];//按照排名重新存储a
}

void dc3(int r[], int sa[], int n, int m){//n=strlen+1,最后一位补0
    int i, j, *rn = r+n, *san = sa+n, ta=0, tb=(n+1)/3, tbc=0, p;
    r[n] = r[n+1] = 0;
    for(i = 0; i < n; ++i)
        if(i%3!=0)  Ra[tbc++] = i;
    Rsort(r+2, Ra, Rb, tbc, m);
    Rsort(r+1, Rb, Ra, tbc, m);
    Rsort(r, Ra, Rb, tbc, m);
    rn[F(Rb[0])] = 0;  p = 1;
    for(i = 1; i < tbc ; ++i)
        rn[F(Rb[i])] = c0(r, Rb[i-1], Rb[i]) ? p-1 : p++;
    if(p < tbc)
        dc3(rn, san, tbc, p);
    else
        for(i=0;i<tbc;i++)
            san[rn[i]] = i;
    for(i = 0; i < tbc; ++i)
        if(san[i]<tb)
            Rb[ta++] = san[i]*3;
    if(n%3==1)
        Rb[ta++]=n-1;
    Rsort(r, Rb, Ra, ta, m);
    for(i = 0; i < tbc; ++i)
        Rv[Rb[i] = G(san[i])] = i;
    for(i=0,j=0,p=0; i<ta && j<tbc; p++)
        sa[p] = c12(Rb[j]%3, r, Ra[i], Rb[j]) ? Ra[i++] : Rb[j++];
    while(i < ta)
        sa[p++] = Ra[i++];
    while(j < tbc)
        sa[p++] = Rb[j++];
}

int ranks[maxn], height[maxn];//height表示与之前一个的最长公共前缀
void calheight(int r[], int sa[], int n){
    int i, j, k = 0;
    for(i = 1; i <= n; ++i)//sa[0]指到了末尾,排名从1开始
        ranks[sa[i]] = i;
    for(i = 0; i < n; height[ranks[i++]] = k){
        k ? k-- : 0;  j = sa[ranks[i]-1];
        while(r[i+k]==r[j+k])
            ++k;
    }
}
char st[maxn];
int source[maxn*3], sa[maxn*3];
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值