<|instruction|>
Solve the below problem. The solution should start with an abridged problem statement. Then key observations. Then full solution based on the observations. Then C++ and Python implementations with comments.

155. Cartesian Tree
time limit per test: 0.25 sec.
memory limit per test: 65536 KB
input: standard input
output: standard output



Let us consider a special type of binary search trees, called cartesian trees. Recall that a binary searchtree is a rooted ordered binary tree, such that for its every node x the following condition is satisfied: each node in its left subtree has the key less than the key of x, and each node in its right subtree has the key greater than the key of x.
That is, if we denote the left subtree of the node x by L(x), its right subtree by R(x) and its key by kx, for each node x we will have
  * if y in L(x) then ky < kx
  * if z in R(x) then kz > kx
The binary search tree is called cartesian if its every node x in addition to the main key kx also has an auxiliary key that we will denote by ax, and for these keys the heap condition is satisfied, that is
  * if y is the parent of x then ay < ax
Thus a cartesian tree is a binary rooted ordered tree, such that each of its nodes has a pair of two keys (k, a) and three conditions described are satisfied.
Given a set of pairs, construct a cartesian tree out of them, or detect that it is not possible.

Input
The first line of the input file contains an integer number N - the number of pairs you should build cartesian tree out of (1 <= N <= 50000). The following N lines contain two integer numbers each - given pairs (ki, ai). For each pair |ki|, |ai| <= 30000. All main keys and all auxiliary keys are different, i.e. ki <> kj and ai <> aj for each i <> j.

Output
On the first line of the output file print YES if it is possible to build a cartesian tree out of given pairs or NO if it is not. If the answer is positive, output the tree itself in the following N lines. Let the nodes be numbered from 1 to N corresponding to pairs they contain as these pairs are given in the input file. For each node output three numbers - its parent, its left child and its right child. If the node has no parent or no corresponding child, output 0 instead.
If there are several possible trees, output any one.

Sample test(s)

Input
7
5 4
2 2
3 9
0 5
1 3
6 6
4 11

Output
YES
2 3 6
0 5 1
1 0 7
5 0 0
2 4 0
1 0 0
3 0 0

Note
Author:	Andrew Stankevich
Resource:	ACM ICPC 2002-2003 NEERC, Northern Subregion
Date:	November, 2002

<|response|>
1. Abridged Problem Statement  
You are given N distinct pairs (k_i, a_i). Construct a binary tree of these N nodes satisfying:  
  – It is a binary search tree by key k (in‐order traversal visits nodes in ascending k).  
  – It is a min‐heap by auxiliary key a (each parent’s a is strictly less than its children’s a).  
If such a “Cartesian tree” exists (it always does when all keys are distinct), print YES and for each node i (in input order 1…N) output three integers: its parent index, its left‐child index, and its right‐child index (use 0 if absent).

2. Key Observations  
• In any BST with distinct k’s, the in‐order sequence of nodes must be the nodes sorted by k.  
• Once you fix that sequence, the heap‐property on a uniquely determines the tree.  
• There is a well‐known O(N) method using a monotonic stack over the a‐values when you process nodes in ascending k.  

3. Full Solution Approach  
1. Read the N pairs, remembering each node’s original index (1…N).  
2. Sort the nodes by k in ascending order.  
3. Prepare arrays parent[ ], left[ ], right[ ] of size N, initialized to –1 (meaning “none”).  
4. Maintain an initially empty stack S of node indices. The stack will have strictly increasing a‐values from bottom to top.  
5. For each node idx in the sorted‐by‐k order:  
   a. Set last = –1.  
   b. While S is nonempty and a[S.top] > a[idx]:  
        pop S.top into last.  
   c. If last ≠ –1, then we popped some nodes with larger a; the last popped becomes the left child of idx:  
        parent[last] = idx;  
        left[idx]  = last;  
   d. If S is still nonempty, its top has a smaller a, so that node becomes parent of idx on the right:  
        parent[idx]    = S.top;  
        right[S.top]  = idx;  
   e. Push idx onto S.  
6. After all nodes are processed, the unique root is at the bottom of S (its parent remains –1).  
7. Output “YES”, then for i=1…N (in input order) print (parent[i]+1, left[i]+1, right[i]+1), converting any –1 to 0.

Time complexity: O(N log N) for sorting + O(N) for the stack algorithm. Memory O(N).

4. C++ Implementation with Detailed Comments  
```cpp
#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int N;
    cin >> N;
    // Read pairs (k, a) and store original index
    struct Node { int k, a, idx; };
    vector<Node> nodes(N);
    for (int i = 0; i < N; i++) {
        cin >> nodes[i].k >> nodes[i].a;
        nodes[i].idx = i; 
    }

    // Sort by main key k to enforce BST in-order
    sort(nodes.begin(), nodes.end(),
         [](auto &u, auto &v){ return u.k < v.k; });

    // parent/left/right arrays, -1 means “no connection”
    vector<int> parent(N, -1), leftC(N, -1), rightC(N, -1);

    // Monotonic stack of indices (into nodes[]). 
    // The a-values of nodes[stack[i]] are strictly increasing.
    vector<int> st;
    st.reserve(N);

    // Build the Cartesian tree in sorted-k order
    for (auto &nd : nodes) {
        int cur = nd.idx;    // original index of this node
        int last = -1;
        // Pop until the top's a <= current a
        while (!st.empty() && nodes[ st.back() ].a > nd.a) {
            last = st.back();
            st.pop_back();
        }
        // The last popped (largest among them) becomes left child of cur
        if (last != -1) {
            parent[last] = cur;
            leftC[cur]    = last;
        }
        // If stack still has a node, it has smaller a => it becomes parent on the right
        if (!st.empty()) {
            parent[cur]      = st.back();
            rightC[st.back()] = cur;
        }
        // Push current node onto stack
        st.push_back(cur);
    }

    // Output result
    cout << "YES\n";
    // Convert -1 to 0 and shift to 1-based indexing
    for (int i = 0; i < N; i++) {
        int p = (parent[i] == -1 ? 0 : parent[i] + 1);
        int l = (leftC[i]  == -1 ? 0 : leftC[i]  + 1);
        int r = (rightC[i] == -1 ? 0 : rightC[i] + 1);
        cout << p << ' ' << l << ' ' << r << "\n";
    }
    return 0;
}
```

5. Python Implementation with Detailed Comments  
```python
import sys
def main():
    data = sys.stdin.read().split()
    it = iter(data)
    N = int(next(it))
    # Read (k, a, original_index)
    nodes = []
    for i in range(N):
        k = int(next(it)); a = int(next(it))
        nodes.append((k, a, i))
    # Sort by k to fix in-order
    nodes.sort(key=lambda x: x[0])

    parent = [-1]*N
    leftC  = [-1]*N
    rightC = [-1]*N

    stack = []  # will store tuples (k, a, idx), but we only need a & idx

    for k, a, idx in nodes:
        last = -1
        # Pop all with larger a
        while stack and stack[-1][1] > a:
            _, _, popped_idx = stack.pop()
            last = popped_idx
        # Attach last popped as left child
        if last != -1:
            parent[last] = idx
            leftC[idx]   = last
        # If anything remains, attach current as right child
        if stack:
            _, _, top_idx = stack[-1]
            parent[idx]     = top_idx
            rightC[top_idx] = idx
        # Push current onto stack
        stack.append((k, a, idx))

    # Print the result
    out = ["YES"]
    for i in range(N):
        p = 0 if parent[i] < 0 else parent[i] + 1
        l = 0 if leftC[i]  < 0 else leftC[i]  + 1
        r = 0 if rightC[i] < 0 else rightC[i] + 1
        out.append(f"{p} {l} {r}")
    sys.stdout.write("\n".join(out))

if __name__ == "__main__":
    main()
```