【后缀数组】后缀排序

最近几天有很多题目没有写,尽量补上吧。

hz2016评测《《点击访问

caioj《《点击访问

后缀数组》后缀自动机

树状数组》线段树

其实两种都是用一个特殊的简单结构,维护一部分高级算法的查询结构。后缀自动机顾名思义,就是处理后缀的啦,这道题是模板题,把数组的所有后缀按照大到小排序。具体还是看代码注释吧,结合代码会比较好理解。
#include<map>
#include<queue>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define Maxchar 1524288 //1000000 +2^19
#define Maxs 30
#define mes(x,y) memset(x,y,sizeof(x));
#define mpy(x,y) memcpy(x,y,sizeof(x))
#define INF 2147483647
using namespace std;
int a[Maxchar+1],tt[Maxchar+1];
char s[Maxchar+1];
int Rank[Maxchar+1],sa1[Maxchar+1],Rank2[Maxchar+1],sa2[Maxchar+1],Rsort[Maxchar+1];
//Rank名次数组: 你排第几?sa后缀数组:排第几的是谁?(记录是的起始位置) 后面的数字表示第几关键字
void get_sa(int n,int m){
    memcpy(Rank,a,sizeof(Rank));
    //预处理第一关键字的排名:对长度为1的字符串进行基数排序,求出sa 
    memset(Rsort,0,sizeof(Rsort));
    for(int i=1;i<=n;i++)Rsort[Rank[i]]++;
    for(int i=1;i<=m;i++)Rsort[i]+=Rsort[i-1];
    for(int i=n;i>=1;i--)sa1[Rsort[Rank[i]]--]=i;
    int ln=1,p=0;//ln为当前处理好的子串的长度,p表示有多少不相同的子串
    while(p<n){//现在处理的是长度为ln*2的子串,开始将两个关键字合并排序
    //为啥不写ln<=n?因为有可能不需要排到ln=n就排完了,而当p==n就说明全部字符串不同,后面再也不会改变
        int k=0;//处理第二关键字的排名:
        for(int i=n-ln+1;i<=n;i++)sa2[++k]=i;//先把要补0的后缀处理好,他们肯定在前面 
        for(int i=1;i<=n;i++)if(sa1[i]-ln>0)sa2[++k]=sa1[i]-ln;
		//sa1[i]是sa1[i]-ln的第二关键字,因为我们枚举的是第二关键字的排名 
        //sa2记录sa1[i]-ln的第二关键字的排名,指向sa1[i]-ln
        memset(Rsort,0,sizeof(Rsort));
        for(int i=1;i<=n;i++)Rsort[Rank[i]]++;
        for(int i=1;i<=m;i++)Rsort[i]+=Rsort[i-1]; 
        for(int i=n;i>=1;i--)sa1[Rsort[Rank[sa2[i]]]--]=sa2[i];
        for(int i=1;i<=n;i++)tt[i]=Rank[i];//由于Rank会改变,判断不了一、二关键字是否相等
        //用sa得到新的Rank数组,为什么预处理的时候不能求出Rank?因为原来的Rank没有两个关键字
        p=1;Rank[sa1[1]]=1;
        for(int i=2;i<=n;i++){
            if(tt[sa1[i]]!=tt[sa1[i-1]]||tt[sa1[i]+ln]!=tt[sa1[i-1]+ln] )p++;
            //一二关键字其中一个不同,前后的字符串不同 
            Rank[sa1[i]]=p;
        } 
        m=p;ln*=2;
    }
} 
int main(){
    scanf("%s",s+1);
    int len=strlen(s+1);
    for(int i=1;i<=len;i++)a[i]=s[i]-'a'+1;
    get_sa(len,Maxs+1);
    for(int i=1;i<len;i++)printf("%d ",sa1[i]);printf("%d\n",sa1[len]);
    return 0;
}
具体就是这样啦,大家赶快做题吧。

查看原文:http://hz2016.tk/blog/?p=28
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值