Kluczem do rozwiązania jest połączenie rozwiązania zachłannego oraz leniwego
podejmowania decyzji.
Permutacja
O tym, czy zamieniamy elementy miejscami, będziemy decydować leniwie.
Na początku dla żadnego kroku nie mamy podjętej decyzji.
Następnie, podczas przeglądania elementu
Informacje o wartościach permutacji będziemy reprezentować w postaci acyklicznego grafu. Wierzchołek node grafu może być dwóch rodzajów: albo ustaloną wartością, albo wartością zależną od pewnej decyzji.
Jeśli jest ustaloną wartością, to trzymamy ją w składowej value. Jeśli natomiast zależy od pewnej decyzji, to trzymamy składowe: fixed -- wskaźnik na informację o decyzji, le -- wskaźnik na wierzchołek, który zawiera informacje o wartości w przypadku, gdy decyzja będzie „nie zamieniamy”, ri -- wskaźnik na wierzchołek, który zawiera informacje o wartości dla decyzji „zamieniamy”.
Dla wierzchołka potrzebujemy dwóch operacji: ustalenie jaka jest jego najmniejsza możliwa wartość oraz wykonanie niezbędnych decyzji, żeby ustawić taką wartość.
W przypadku wyznaczania minimum, przechodzimy po grafie. Dla wierzchołka z ustaloną wartością zwracamy value, a dla nieustalonego patrzymy na jego decyzję. Jeśli nie była podjęta, to zwracamy minimum z rekurencyjnie obliczonych wartości dla wierzchołków le i ri, a jeśli była, to wartość z odpowiedniego z tych wierzchołków.
Mając minimalną wartość, jeszcze raz przechodzimy graf, aby ustalić wymuszone decyzje. Dla wierzchołka bez podjętej decyzji ustalamy ją tak, aby uzyskać minimum. Dla uproszczenia implementacji, jeśli decyzja będzie „zamieniamy”, to możemy po prostu zamienić miejscami wartości wierzchołków le i ri.
Poniżej implementacja struktury wierzchołka:
struct node { node* le; node* ri; bool* fixed; int value; int minimum() { if (!le) { return value; } else if (*fixed) { return le->minimum(); } else { return min(le->minimum(), ri->minimum()); } } void fix(int val) { if (!le) { assert(val == value); } else { if (!*fixed && ri->minimum() == val) { swap(*le, *ri); } *fixed = true; le->fix(val); } } };
Teraz wystarczy stworzyć
Na końcu
Tak więc całe rozwiązanie będzie miało złożoność czasową
const int N = 210000; int n,a[N]; node* no[N]; bool is_fixed[N]; int main() { scanf("%d",&n); REP(i,n) { scanf("%d",&a[i]); no[i] = new node{ nullptr, nullptr, nullptr, a[i] }; } REP(i,n-1) { node* le = no[i/2]; node* ri = no[i+1]; no[i/2] = new node{ le, ri, &is_fixed[i], -1 }; no[i+1] = new node{ ri, le, &is_fixed[i], -1 }; } REP(i,n) { int v = no[i]->minimum(); no[i]->fix(v); printf("%d ",v); } printf("\n"); }