#include <fstream>
#include <iostream>
#include <cstdlib>
using namespace std;
const int nil = 0x3f3f3f3f;
struct Per{
int val, nr;
void addOne(){
nr++;
}
inline bool operator<(Per P){
return val < P.val;
}
inline bool operator==(Per P){
return val == P.val;
}
inline bool operator<=(Per P){
return val <= P.val;
}
};
template<class Data, const int cap, const int T>
class Btree{
Data keyBuff[ (2 * T - 1) * cap / (T - 1) ];
int sonBuff[ 2 * T * cap / (T - 1) ], size[ cap / (T - 1) ], freeStack[ 1 + cap / (T - 1) ], root, stepSize;
inline Data* getKeyArray(int x){
return keyBuff + (2 * T - 1) * x;
}
inline int* getSonArray(int x){
return sonBuff + 2 * T * x;
}
inline bool isFull(int x){
return 1 + size[x] == 2 * T;
}
inline bool isLeaf(int x){
return sonBuff[2 * T * x] == nil;
}
int allocNode(){
int nod = freeStack[ freeStack[0]-- ];
*getSonArray(nod) = nil;
size[nod] = 0;
return nod;
}
void dealloc(int nod){
freeStack[ ++freeStack[0] ] = nod;
}
int bSearch(Data* v, Data K, int N){
int ans = 0;
for (int step = stepSize, P = step ; step ; step >>= 1, P = ans ^ step)
if ( P < N && v[P] <= K )
ans = P;
return ans;
}
void splitSon(int nod, int index){
Data *key = getKeyArray(nod);
int *son = getSonArray(nod);
int st = son[index], dr = allocNode();
Data *keySt = getKeyArray(st) + T, *keyDr = getKeyArray(dr);
int *sonSt = getSonArray(st) + T, *sonDr = getSonArray(dr);
for (int i = size[nod] ; i > index ; i--){
key[i] = key[i - 1];
son[i + 1] = son[i];
}
key[index] = keySt[-1];
son[index + 1] = dr;
size[nod]++;
size[st] = T - 1;
for (int i = 0 ; i < T - 1 ; i++)
keyDr[i] = keySt[i];
for (int i = 0 ; i < T ; i++)
sonDr[i] = sonSt[i];
}
int browseTree(Data K, bool doSplits){
if ( doSplits && isFull(root) ){
int P = allocNode();
*getSonArray(P) = root;
root = P;
splitSon(root, 0);
}
Data *key;
int nod = root, index, *son;
while (!isLeaf(nod)){
key = getKeyArray(nod);
son = getSonArray(nod);
index = bSearch(key, K, size[nod]);
if ( doSplits && isFull(son[index]) ){
splitSon(nod, index);
index++;
}
if (key[index] == K)
return nod;
nod = son[index];
}
return nod;
}
Data findMin(int nod, bool deleteIt){
while (!isLeaf(nod))
nod = *getSonArray(nod);
if (deleteIt){
Data *key = getKeyArray(nod);
int ans = key[0];
size[nod]--;
for (int i = 0 ; i < size[nod] ; i++)
key[i] = key[i + 1];
return ans;
}
return *getKeyArray(nod);
}
Data findMax(int nod, bool deleteIt){
while (!isLeaf(nod))
nod = *(getSonArray(nod) + size[nod]);
if (deleteIt)
return *(getSonArray(nod) + (--size[nod]));
return *(getKeyArray(nod) + size[nod] - 1);
}
void parcurge(int nod, void (*work)(Data)){
Data *key = getKeyArray(nod);
if (isLeaf(nod)){
for (int i = 0 ; i < size[nod] ; i++)
work( key[i] );
return;
}
int *son = getSonArray(nod);
for (int i = 0 ; i < size[nod] ; i++){
parcurge(son[i], work);
work(key[i]);
}
parcurge( son[ size[nod] ], work );
}
public:
Btree(){
freeStack[0] = sizeof(freeStack) / sizeof(int) - 1;
for (int i = 1 ; i <= freeStack[0] ; i++)
freeStack[i] = i;
root = allocNode();
stepSize = 1;
while (stepSize < T)
stepSize <<= 1;
}
void insert(Data K){
/*
int nod = browseTree(K, true);
Data *key = getKeyArray(nod);
if (!isLeaf(nod) || key[ bSearch(key, K, size[nod]) ] == K)
return;
int index;
for (index = size[nod] ; index && K < key[index - 1] ; index--)
key[index] = key[index - 1];
key[index] = K;
size[nod]++;
*/
int nod = browseTree(K, true);
Data *key = getKeyArray(nod);
int index = bSearch(key, K, size[nod]);
if (key[index] == K){
key[index].addOne();
return;
}
for (index = size[nod] ; index && K < key[index - 1] ; index--)
key[index] = key[index - 1];
key[index] = K;
size[nod]++;
}
bool contains(Data K){
int nod = browseTree(K, false), *key = getKeyArray(nod);
return key[ bSearch(key, K, size[nod]) ] == K;
}
void erase(Data K){
int nod = browseTree(K, false), *key = getKeyArray(nod);
int index = bSearch(key, K, size[nod]);
if (key[index] != K)
return;
if (isLeaf(nod)){
for (int i = index + 1 ; i < size[nod] ; i++)
key[i - 1] = key[i];
size[nod]--;
return;
}
int* son = getSonArray(nod);
int st = son[index], dr = son[index + 1];
if (T <= size[st]) {
key[index] = findMax( st, true );
return;
}
if (T <= size[dr]) {
key[index] = findMin( dr, true );
return;
}
Data *keySt = getKeyArray(st), *keyDr = getKeyArray(dr);
int *sonSt = getSonArray(st), *sonDr = getSonArray(dr);
key[index] = keySt[ size[st] - 1 ];
son[index + 1] = sonDr[ size[dr] ];
for (int i = size[st] - 1, j = 0 ; j < size[dr] ; i++, j++){
keySt[i] = keyDr[j];
sonSt[i] = sonDr[j];
}
size[st] += size[dr] - 1;
dealloc(dr);
}
int getMinimum(){
return findMin(root, false);
}
int getMaximum(){
return findMax(root, false);
}
void inOrder( void (*work)(Data) ){
parcurge(root, work);
}
};
Btree<Per, 500000, 100> B;
ifstream in("algsort.in");
ofstream out("algsort.out");
void print(Per X){
while (X.nr--)
out << X.val << " ";
}
int main(){
int n;
Per P; P.nr = 1;
in >> n;
while (n--){
in >> P.val;
B.insert( P );
}
B.inOrder(print);
out << '\n';
return 0;
}