#include <cstdio>
#include <ext/pb_ds/assoc_container.hpp>
using namespace std;
using namespace __gnu_pbds;

// we will use this class, it is able to do everything
// simple map<int, int> can do, and as we can see, much more!
typedef tree<int, int, less<int>, rb_tree_tag> Tree;
// another choice is to use splay_tree_tag for splay tree implementation

void print_tree(Tree::node_iterator it, Tree::node_iterator null, int indent = 0)
{
    if (it == null)
        return;
    // that's how we can access left child and right child
    // as I understand, there is no way to access parent node
    print_tree(it.get_l_child(), null, indent + 1);
    for (int i = 0; i < indent; i++)
        printf("    ");
    printf("(%d %d)\n", (**it).first, (**it).second);
    // of course this is equal to:
    // printf("(%d %d)\n", (*it)->first, (*it)->second);
    print_tree(it.get_r_child(), null, indent + 1);
}

int main()
{
    Tree X;
    // we can use X like usual map container
    for (int i = 0; i < 15; i++)
        X[i * i] = i ^ (i + 1);
    // we can iterate over it using iterators, begin() and end()
    for (Tree::iterator it = X.begin(); it != X.end(); it++)
        printf("%d %d\n", it->first, it->second);
    /* output:
     * 0 1
     * 1 3
     * 4 1
     * 9 7
     * 16 1
     * 25 3
     * 36 1
     * 49 15
     * 64 1
     * 81 3
     * 100 1
     * 121 7
     * 144 1
     * 169 3
     * 196 1
     */
    // but implementation gives us cool interface to access nodes of the tree!
    Tree::node_iterator root = X.node_begin();
    // for example we can print value at the root of the tree
    // root has type node_iterator
    // *root has type point_iterator == iterator (these two types are synonimic for trees)
    // **root has containing type (pair<int, int> in our case)
    printf("%d %d\n", (**root).first, (**root).second);
    // output: 9 7 
    // let's traverse the tree using methods get_l_node() and get_r_node()
    print_tree(root, X.node_end()); // X.node_end() defines null (leaf terminator) for this tree
    /* output:
     *         (0 1)
     *     (1 3)
     *         (4 1)
     * (9 7)
     *            (16 1)
     *         (25 3)
     *             (36 1)
     *     (49 15)
     *             (64 1)
     *         (81 3)
     *                 (100 1)
     *             (121 7)
     *                     (144 1)
     *                 (169 3)
     *                     (196 1)
     */
    Tree Y;
    // Now we are going to split by the key 42 
    // (42 and greater are moving to the right operand Y, other keys remain in X tree)
    X.split(42, Y);
    print_tree(X.node_begin(), X.node_end());
    /* output:
     *         (0 1)
     *     (1 3)
     *         (4 1)
     * (9 7)
     *         (16 1)
     *     (25 3)
     *         (36 1)
     */
    print_tree(X.node_begin(), X.node_end());
    /* output:
     *         (0 1)
     *     (1 3)
     *         (4 1)
     * (9 7)
     *         (16 1)
     *     (25 3)
     *         (36 1)
     */
    // notice that both parts are absolutely balanced!
    // we can merge them back
    X.join(Y);
    printf("%d\n", (int)X.size());
    // output: 15 
    // we can find lower bound for a key in this tree
    Tree::iterator it = (X.lower_bound(42));
    // it returns a usual iterator, not a node_iterator
    // it's easy to understand that it is more formally correct: one can possibly
    // use this tree as usual map, and it will be a big surprise, that lower_bound
    // returns some strange node_iterator type instead of usual iterator
    printf("%d %d\n", it->first, it->second);
    // output: 49 15 
    // but now some strange effect: we can simply cast node_iterator to iterator
    // with dereferensing (*node_iterator = iterator), but I didn't found
    // any other way to do the reverse cast (from iterator to node_iterator) except this:
    Tree::node_iterator n_it = it.m_p_nd;
    printf("%d %d\n", (*n_it)->first, (*n_it)->second);
    // output: 49 15
    // .m_p_nd field is left public, that is strange for c++-library style, but
    // I don't know other ways to convert iterator to node_iterator. Any ideas?
        
    return 0;
}
