后缀数组 倍增法
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#define maxn 200010
using namespace std;
int k, n;
int _rank[maxn*2], tem[maxn*2];
int sa[maxn*2];
int N, A[maxn*2];
int rev[maxn*2];
bool compare_sa(int i, int j) {
if(_rank[i] != _rank[j]) return _rank[i] < _rank[j];
else {
int ri = i+k <= n ? _rank[i+k] : -1;
int rj = j+k <= n ? _rank[j+k] : -1;
return ri < rj;
}
}
void construct_sa(int S[], int d) {
n = d;
for(int i = 0; i <= n; ++ i) {
sa[i] = i;
_rank[i] = i < n ? S[i] : -1;
}
for(k = 1; k <= n; k *= 2) {
sort(sa, sa+n+1, compare_sa);
tem[sa[0]] = 0;
for(int i = 1; i <= n; ++ i) {
tem[sa[i]] = tem[sa[i-1]] + (compare_sa(sa[i-1], sa[i]) ? 1 : 0);
}
for(int i = 0; i <= n; ++ i) {
_rank[i] = tem[i];
}
}
}
void solve() {
reverse_copy(A, A+N, rev);
construct_sa(rev, N);
int p1;
for(int i = 0; i < N; ++ i) {
p1 = N-sa[i];
if(p1 >= 1 && N-p1 >= 2) break;
}
int m = N - p1;
reverse_copy(A+p1, A+N, rev);
reverse_copy(A+p1, A+N, rev+m);
construct_sa(rev, m*2);
int p2;
for(int i = 0; i <= 2*m; ++ i) {
p2 = p1+m-sa[i];
if(p2-p1 >= 1 && N-p2 >= 1) break;
}
reverse(A, A+p1);
reverse(A+p1, A+p2);
reverse(A+p2, A+N);
for(int i = 0; i < N; ++ i) printf("%d\n", A[i]);
}
int main()
{
scanf("%d", &N);
memset(A, 0, sizeof(A));
for(int i = 0; i < N; ++ i) {
scanf("%d", &A[i]);
}
solve();
return 0;
}