標籤:
這是一道模板題。
讀入一個長度為 n 的由小寫英文字母組成的字串,請把這個字串的所有非空尾碼按字典序從小到大排序,然後按順序輸出尾碼的第一個字元在原串中的位置。位置編號為 1 到 n。
除此之外為了進一步證明你確實有給尾碼排序的超能力,請另外輸出 n−1 個整數分別表示排序後相鄰尾碼的最長公用首碼的長度。
輸入格式
一行一個長度為 n 的僅包含小寫英文字母的字串。
輸出格式
第一行 n 個整數,第 i 個整數表示排名為 i 的尾碼的第一個字元在原串中的位置。
第二行 n−1 個整數,第 i 個整數表示排名為 i 和排名為 i+1 的尾碼的最長公用首碼的長度。
範例一input
ababa
output
5 3 1 4 21 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;}View Code
UOJ#35 尾碼排序