UOJ#35 后缀排序
这是一道模板题。
读入一个长度为 n 的由小写英文字母组成的字符串,请把这个字符串的所有非空后缀按字典序从小到大排序,然后按顺序输出后缀的第一个字符在原串中的位置。位置编号为 1 到 n。
除此之外为了进一步证明你确实有给后缀排序的超能力,请另外输出 n−1 个整数分别表示排序后相邻后缀的最长公共前缀的长度。
输入格式
一行一个长度为 n 的仅包含小写英文字母的字符串。
输出格式
第一行 n 个整数,第 i 个整数表示排名为 i 的后缀的第一个字符在原串中的位置。
第二行 n−1 个整数,第 i 个整数表示排名为 i 和排名为 i+1 的后缀的最长公共前缀的长度。
样例一
input
ababa
output
5 3 1 4 2 1 3 0 2
explanation
排序后结果为:
- a
- aba
- ababa
- ba
- baba
限制与约定
1≤n≤105
时间限制:1s
空间限制:256MB
我的后缀平衡树终于过了
#include<cstdio> #include<cctype> #include<queue> #include<ctime> #include<cstring> #include<algorithm> #define mid l+r>>1 #define rep(s,t) for(int i=s;i<=t;i++) #define ren for(int i=first[x];i!=-1;i=next[i]) using namespace std; inline int read() { int x=0,f=1;char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } const int maxn=100010; typedef long long ll; int h[maxn],ch[maxn][2],c[maxn],tot,rt; ll rk[maxn]; void rebuild(int o,ll l,ll r) { if(!o) return;rk[o]=l+r; rebuild(ch[o][0],l,mid);rebuild(ch[o][1],mid,r); } void rotate(int& o,int d,ll l,ll r) { int k=ch[o][d^1];ch[o][d^1]=ch[k][d];ch[k][d]=o;o=k; rebuild(o,l,r); } int cmp(int x,int y) {return c[x]<c[y]||(c[x]==c[y]&&rk[x-1]<rk[y-1]);} void insert(int& o,ll l,ll r) { if(!o) {o=tot;rk[o]=l+r;return;} if(cmp(tot,o)) {insert(ch[o][0],l,mid);if(h[ch[o][0]]>h[o]) rotate(o,1,l,r);} else {insert(ch[o][1],mid,r);if(h[ch[o][1]]>h[o]) rotate(o,0,l,r);} } void insert(int x) { c[++tot]=x;h[tot]=rand()*rand(); insert(rt,1,1ll<<61); } void print(int o) { if(!o) return; print(ch[o][0]); printf("%lld ",rk[o]); print(ch[o][1]); } int n,sa[maxn],rank[maxn],height[maxn]; int cmp2(int a,int b) {return rk[n-a+1]<rk[n-b+1];} char s[maxn]; int main() { srand(time(0)); scanf("%s",s);n=strlen(s); rep(1,n) insert(s[n-i]-'a'+1),sa[i]=i; sort(sa+1,sa+n+1,cmp2); rep(1,n) rank[sa[i]]=i,printf("%d ",sa[i]);puts(""); for(int i=1,j,k=0;i<=n;i++) { j=sa[rank[i]-1]; while(s[i+k-1]==s[j+k-1]) k++; height[rank[i]]=k?k--:k; } rep(2,n) printf("%d ",height[i]); return 0; }