protagonist

后缀排序

题目描述

读入一个长度为 nn 的由大小写英文字母或数字组成的字符串,请把这个字符串的所有非空后缀按字典序从小到大排序,然后按顺序输出后缀的第一个字符在原串中的位置。位置编号为 11 到 nn。

输入输出格式

输入格式:

 

一行一个长度为 nn 的仅包含大小写英文字母或数字的字符串。

 

输出格式:

 

一行,共n个整数,表示答案。

 

输入输出样例

输入样例#1: 复制
ababa
输出样例#1: 复制
5 3 1 4 2

说明

n <= 10^6

思路:后缀数组模板题。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i <= (b); ++ i)
#define REP(j, a, b) for(int j = (a); j <= (b); ++ j)
#define PER(i, a, b) for(int i = (a); i >= (b); -- i)
using namespace std;
template <class T>
inline void rd(T &ret){
    char c;
    ret = 0;
    while ((c = getchar()) < '0' || c > '9');
    while (c >= '0' && c <= '9'){
        ret = ret * 10 + (c - '0'), c = getchar();
    }
}
const int maxn=1e6+10;
char str[maxn];
int len,m,sa[maxn],rk[maxn],tp[maxn],ton[maxn];
void rsort(){
     for(int i=1;i<=m;i++)ton[i]=0;
     for(int i=1;i<=len;i++)ton[rk[i]]++;
     for(int i=1;i<=m;i++)ton[i]+=ton[i-1];
     for(int i=len;i>=1;i--)sa[ton[rk[tp[i]]]--]=tp[i];
}
int super(){
      for(int i=1;i<=len;i++)rk[i]=str[i],tp[i]=i;
      rsort();
      for(int w=1,p=0;p<len&&w<=len;m=p,w*=2){
           p=0;
           for(int i=len-w+1;i<=len;i++)tp[++p]=i;
           for(int i=1;i<=len;i++){
               if(sa[i]>w)tp[++p]=sa[i]-w;
           }
           rsort();
           swap(rk,tp);
           rk[sa[1]]=p=1;
           for(int i=2;i<=len;i++){
               rk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&(tp[sa[i-1]+w]==tp[sa[i]+w]))?p:++p;
           }
           if(p>=len)break;
      }
}
int main(){
     cin>>str+1;
     len=strlen(str+1);
     m=127;
     super();
     REP(i,1,len)cout<<sa[i]<<' ';
     return 0;
}

 

posted @ 2019-02-16 12:30  czy-power  阅读(411)  评论(0编辑  收藏  举报