Next Permutation on Subsegment

Revision en11, by Guslix, 2021-08-20 15:34:52

Is it yet another range query for $$$O(log N)$$$? RSQ, RMQ, average, reversal on subsegment and even... next_permutation? Yes, of course! This problem an be solved using a simple and very old Narayana's algorithm. This algorithm invented by Indian mathematician Pandit Narayana more than 600 years ago.

Given array $$$a$$$. How to go to its next permutation?

  1. Find the longest non-increasing suffix of the array (LNIS). If whole array is non-increasing, permutations are exhausted.

  2. Let LNIS be a suffix $$$k$$$, where $$$k$$$ is position where it begins. Swap previous element, $$$a_{k-1}$$$ and the next largest number (NLN) that exists in suffix $$$k$$$.

  3. Reverse suffix $$$k$$$.

Learn more about Narayana's algorithm

This operations can be performed on a treap! Reversal is known, and swapping is just a combination of split and merge operations. Also we need to find LNIS and NLN. LNIS is sorted by definition, so we can apply binary search in order to find NLN of $$$a_{k-1}$$$.

But to find LNIS is more difficult. Let in each subtree maintain if the elements in this tree are non-increasing. Then recursion on the treap selects at most one subtree each step and find LNIS for $$$O(log N)$$$.

How to maintain this flag? Elements of a tree are non-increasing if and only if both subtrees are with non-increasing elements and last element of left subtree $$$\geq$$$ value of tree's root $$$\geq$$$ first element of right subtree. Empty subtrees don't affect the non-increasing order. Since we need to reverse segments, we should to maintain also a flag of non-decreasing order. These two flags are swapping while reversing.

The Code

Struct node
Lazy propagation of reverse
Recalc of size and other node parameters
Split
Merge
Build a treap from array
Find k, the position of start LNIS
Find the position of NLN
void next_p(int L, int R, treap t=root){
    treap l, r, swap1, swap2, between;
    split(t, t, r, R+1, 0);
    int k = find_k(t, R)+1;
    split(t, l, t, max(L,k), 0);
    t->reversed ^= 1;
    if(k>L) {
        split(l, l, swap1, k-1, 0);
        int nln = find_nln(t, swap1->val, k);
        //pr(nln);
        split(t, between, t, nln, k); split(t, swap2, t, nln+1, nln);
        merge(t, swap1, t); merge(t, between, t); merge(t, swap2, t);
    }
    merge(t, l, t); merge(t, t, r);
}
Tags next permutation, narayana, treap, data structures

History

 
 
 
 
Revisions
 
 
  Rev. Lang. By When Δ Comment
en18 English Guslix 2021-08-21 14:15:26 45
en17 English Guslix 2021-08-20 20:00:01 51
en16 English Guslix 2021-08-20 19:58:14 53
en15 English Guslix 2021-08-20 19:51:12 1 Tiny change: '$O(\log n).$\n\n\n\n<' -> '$O(\log n)$\n\n\n\n<'
en14 English Guslix 2021-08-20 19:31:34 51 (published)
en13 English Guslix 2021-08-20 18:35:11 422
en12 English Guslix 2021-08-20 18:18:48 1405
en11 English Guslix 2021-08-20 15:34:52 1142
en10 English Guslix 2021-08-20 09:41:35 450
en9 English Guslix 2021-08-19 23:59:09 698
en8 English Guslix 2021-08-19 20:59:20 129
en7 English Guslix 2021-08-19 20:20:06 5
en6 English Guslix 2021-08-19 20:19:06 15
en5 English Guslix 2021-08-19 20:15:03 548
en4 English Guslix 2021-08-19 19:55:57 3193
en3 English Guslix 2021-08-19 19:40:49 670
en2 English Guslix 2021-08-19 19:01:53 402
en1 English Guslix 2021-08-19 10:54:29 1255 Initial revision (saved to drafts)