<|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.

263. Towers
time limit per test: 1.25 sec.
memory limit per test: 65536 KB
input: standard
output: standard



Vasya likes to play unusual games very much. One of these games is building towers. Unfortunately he is very tired today and instead of building towers himself, he wants his favorite robot to build towers for him. So, this time, Vasya will be laying on his couch sending commands to his robot.
The process of constructing towers is very easy. Imagine that you have a number of cells in a row. Cells are numbered from 1 to 10^6 and initially are empty. Robot can move to specified cell and put some number of cubes on it. If there are some cubes already on the cell, he will put new cubes on the top of the existing ones.
For two integers i and j (i <= j) the cubes on cells i..j are called 'tower', if on any cell with number k, i <= k <= j, there is a positive number of cubes, and there are no cubes on cell i-1 (or i is the leftmost cell in the row) and cell j+1 (or j is the rightmost cell in the row). Length of the tower is j-i+1 - the number of columns in it.
Within each tower the columns can be numbered from 1 to its length from the left to the right, so instead of giving robot a cell number, Vasya can give robot a tower number and column number within the tower.
As you can guess, your task is to write a robot that will process commands from Vasya. Robot must be able to build towers and respond to simple questions (see below).
Here is the list of available commands:

Actions:

put <x> <c> - put c cubes on cell x

tput <t> <x> <c> - put c cubes on column x in tower with number t (towers are numbered from left to the right)



Questions:

towers - print total number of towers built

cubes <t> - print the number of cubes in the tower t

length <t> - print the length of the tower t

tcubes <t> <x> - print the number of cubes in column x of the tower t

Input
The first line of input file contains a number of commands N (1 <= N <= 10^6). Each of the following N lines contains a command.
It's guaranteed that all input commands are correct (cell number c is always in range 1..10^6, tower t always exists, column x inside tower always exists and its corresponding cell number is also in range 1..10^6).
You can assume that no cell will have more than 2^31-1 cubes on it.

Output
For the commands that require printing, output exactly one line according to the format of sample output file below.
Please, do not follow English grammar rules and print '1 towers' instead of '1 tower'. The same applies for printing '1 cubes' and '1th', '2th' and '3th'.

Sample test(s)

Input
22
towers
put 2 5
put 1 6
put 3 6
put 3 3
towers
length 1
put 6 3
put 5 4
length 2
tcubes 2 1
tcubes 2 2
towers
cubes 1
cubes 2
put 4 3
towers
cubes 1
tput 1 6 50
cubes 1
tcubes 1 6
length 1

Output
0 towers
1 towers
length of 1th tower is 3
length of 2th tower is 2
4 cubes in 1th column of 2th tower
3 cubes in 2th column of 2th tower
2 towers
20 cubes in 1th tower
7 cubes in 2th tower
1 towers
30 cubes in 1th tower
80 cubes in 1th tower
53 cubes in 6th column of 1th tower
length of 1th tower is 6

Note
This problem has huge tests. Some read/write routines work very slow in several compilers (especially, C/C++: try to use getc() putc() functions to avoid IO troubles).
Author:	Roman V. Alekseenkov
Resource:	Saratov SU Contest: Golden Fall 2004
Date:	October 2, 2004

<|response|>
## 1. Abridged problem statement

There are `10^6` cells in a row, initially empty. Adding cubes to an empty cell makes it non-empty forever. A **tower** is a maximal contiguous segment of non-empty cells.

Process up to `10^6` commands:

- `put x c`: add `c` cubes to global cell `x`.
- `tput t x c`: add `c` cubes to column `x` of the `t`-th tower.
- `towers`: print the number of towers.
- `cubes t`: print total cubes in the `t`-th tower.
- `length t`: print length of the `t`-th tower.
- `tcubes t x`: print cubes in column `x` of the `t`-th tower.

Towers are numbered from left to right. Columns inside a tower are also numbered from left to right.

---

## 2. Key observations

### Observation 1: Towers never split

Cubes are only added, never removed.

Therefore:

- an empty cell may become non-empty;
- a non-empty cell stays non-empty forever;
- towers can appear, extend, or merge;
- towers never split.

This makes the structure much easier to maintain.

---

### Observation 2: A tower can be represented by one interval

For every current tower, store:

```text
left boundary
right boundary
total number of cubes in the tower
```

Also keep:

```text
height[x] = number of cubes on global cell x
```

Since `x <= 10^6`, a simple array is enough.

---

### Observation 3: We need order statistics

Commands refer to the `t`-th tower from the left.

So we need a data structure that supports:

- ordered towers by left boundary;
- finding the `k`-th tower;
- inserting a new tower;
- deleting a merged tower;
- finding predecessor tower by position.

A randomized treap with subtree sizes is a good fit.

Each treap node represents one tower and is keyed by the tower's left endpoint.

---

## 3. Full solution approach

Maintain an order-statistic treap.

Each node stores:

```text
key       = left endpoint of tower
rightEnd  = right endpoint of tower
sum       = total cubes in this tower
size      = number of nodes in subtree
```

Also maintain:

```text
height[1..10^6]
```

---

### Query: `towers`

The answer is the number of nodes in the treap:

```text
size[root]
```

---

### Query: `length t`

Find the `t`-th tower in the treap.

If its interval is `[l, r]`, print:

```text
r - l + 1
```

---

### Query: `cubes t`

Find the `t`-th tower and print its stored `sum`.

---

### Query: `tcubes t x`

Find the `t`-th tower.

If it starts at `l`, then column `x` corresponds to global cell:

```text
cell = l + x - 1
```

Print:

```text
height[cell]
```

---

### Update: `tput t x c`

Find the `t`-th tower.

Convert local column `x` to a global cell:

```text
cell = tower.left + x - 1
```

Then:

```text
height[cell] += c
tower.sum += c
```

This does not change tower boundaries because the cell is already inside an existing tower.

---

### Update: `put x c`

This is the only operation that can change tower structure.

#### Case 1: `height[x] > 0`

Cell `x` is already occupied.

Only update:

```text
height[x] += c
containingTower.sum += c
```

The containing tower is the tower with largest left endpoint `<= x`.

---

#### Case 2: `height[x] == 0`

Cell `x` becomes occupied.

Check its neighbors:

```text
leftOccupied  = height[x - 1] > 0
rightOccupied = height[x + 1] > 0
```

There are four cases.

---

#### Case 2.1: neither neighbor is occupied

Create a new tower:

```text
[x, x]
```

Insert a new treap node.

---

#### Case 2.2: only left neighbor is occupied

Extend the left tower:

```text
[..., x - 1] -> [..., x]
```

Update its right endpoint and sum.

---

#### Case 2.3: only right neighbor is occupied

Extend the right tower to the left:

```text
[x + 1, ...] -> [x, ...]
```

The right tower starts at `x + 1`. Change its key from `x + 1` to `x`.

This is safe because `x - 1` is empty, so no other tower start lies between `x` and `x + 1`.

---

#### Case 2.4: both neighbors are occupied

Cell `x` connects two towers:

```text
[left tower] x [right tower]
```

Merge them:

```text
left.rightEnd = right.rightEnd
left.sum += c + right.sum
erase right tower
```

---

### Complexity

Let `T` be the current number of towers.

Each treap operation is expected:

```text
O(log T)
```

Therefore each command is processed in expected:

```text
O(log T)
```

Memory usage:

```text
O(10^6 + number of created tower nodes)
```

---

## 4. C++ implementation with detailed comments

```cpp
#include <bits/stdc++.h>
using namespace std;

/*
    Problem constraints are large, so:
    - use fast input/output;
    - store the treap in static arrays instead of using new/delete;
    - use int node indices, where node 0 means null.
*/

const int MAX_CELL = 1000000;
const int MAX_NODES = 1000000 + 5;

/*
    Treap arrays.

    For node v:
    key[v]      = left boundary of the tower
    rightEnd[v] = right boundary of the tower
    sum[v]      = total cubes in this tower
    leftCh[v]   = left child in treap
    rightCh[v]  = right child in treap
    sz[v]       = subtree size
    prior[v]    = random priority
*/

int keyArr[MAX_NODES];
int rightEndArr[MAX_NODES];
long long sumArr[MAX_NODES];

int leftCh[MAX_NODES];
int rightCh[MAX_NODES];
int sz[MAX_NODES];
uint32_t priorArr[MAX_NODES];

int nodeCnt = 0;
int root = 0;

/*
    height[x] = cubes on global cell x.

    We allocate MAX_CELL + 2 so that height[x - 1] and height[x + 1]
    are always safe for x in [1, 10^6].
*/
int heightArr[MAX_CELL + 2];

/* ---------------- Fast random generator for treap priorities ---------------- */

uint32_t rng32() {
    static uint32_t x = 2463534242u;

    // xorshift32
    x ^= x << 13;
    x ^= x >> 17;
    x ^= x << 5;

    return x;
}

/* ---------------- Treap utility functions ---------------- */

int getSize(int v) {
    return v == 0 ? 0 : sz[v];
}

void pull(int v) {
    if (v == 0) return;

    sz[v] = 1 + getSize(leftCh[v]) + getSize(rightCh[v]);
}

int newNode(int l, int r, long long s) {
    ++nodeCnt;

    keyArr[nodeCnt] = l;
    rightEndArr[nodeCnt] = r;
    sumArr[nodeCnt] = s;

    leftCh[nodeCnt] = 0;
    rightCh[nodeCnt] = 0;
    sz[nodeCnt] = 1;
    priorArr[nodeCnt] = rng32();

    return nodeCnt;
}

/*
    Split treap t by key k.

    Result:
    - a contains nodes with key <= k
    - b contains nodes with key > k
*/
void split(int t, int k, int &a, int &b) {
    if (t == 0) {
        a = b = 0;
        return;
    }

    if (k < keyArr[t]) {
        /*
            Current node belongs to the right part.
            Split its left subtree.
        */
        split(leftCh[t], k, a, leftCh[t]);
        b = t;
        pull(b);
    } else {
        /*
            Current node belongs to the left part.
            Split its right subtree.
        */
        split(rightCh[t], k, rightCh[t], b);
        a = t;
        pull(a);
    }
}

/*
    Merge two treaps a and b.

    Requirement:
    every key in a must be <= every key in b.
*/
int mergeTreap(int a, int b) {
    if (a == 0 || b == 0) {
        return a == 0 ? b : a;
    }

    if (priorArr[a] > priorArr[b]) {
        rightCh[a] = mergeTreap(rightCh[a], b);
        pull(a);
        return a;
    } else {
        leftCh[b] = mergeTreap(a, leftCh[b]);
        pull(b);
        return b;
    }
}

/*
    Insert node v into treap t.
*/
int insertNode(int t, int v) {
    if (t == 0) {
        return v;
    }

    if (priorArr[v] > priorArr[t]) {
        split(t, keyArr[v], leftCh[v], rightCh[v]);
        pull(v);
        return v;
    }

    if (keyArr[v] < keyArr[t]) {
        leftCh[t] = insertNode(leftCh[t], v);
    } else {
        rightCh[t] = insertNode(rightCh[t], v);
    }

    pull(t);
    return t;
}

/*
    Erase node with exact key k from treap t.
*/
int eraseNode(int t, int k) {
    if (keyArr[t] == k) {
        return mergeTreap(leftCh[t], rightCh[t]);
    }

    if (k < keyArr[t]) {
        leftCh[t] = eraseNode(leftCh[t], k);
    } else {
        rightCh[t] = eraseNode(rightCh[t], k);
    }

    pull(t);
    return t;
}

/*
    Return the zero-based k-th node by key order.
*/
int kthNode(int t, int k) {
    while (t != 0) {
        int leftSize = getSize(leftCh[t]);

        if (k < leftSize) {
            t = leftCh[t];
        } else if (k == leftSize) {
            return t;
        } else {
            k -= leftSize + 1;
            t = rightCh[t];
        }
    }

    return 0; // Should never happen for valid input.
}

/*
    Find node with exact key k.
*/
int findNode(int t, int k) {
    while (t != 0) {
        if (keyArr[t] == k) return t;

        if (k < keyArr[t]) {
            t = leftCh[t];
        } else {
            t = rightCh[t];
        }
    }

    return 0;
}

/*
    Find node with the largest key <= x.
*/
int predecessorNode(int t, int x) {
    int ans = 0;

    while (t != 0) {
        if (keyArr[t] <= x) {
            ans = t;
            t = rightCh[t];
        } else {
            t = leftCh[t];
        }
    }

    return ans;
}

/* ---------------- Fast input/output ---------------- */

namespace FastIO {
    const int IN_BUF = 1 << 16;
    char inBuf[IN_BUF];
    int inPos = 0, inLen = 0;

    int getChar() {
        if (inPos == inLen) {
            inLen = (int)fread(inBuf, 1, IN_BUF, stdin);
            inPos = 0;
        }

        return inPos < inLen ? inBuf[inPos++] : EOF;
    }

    int skipSpaces() {
        int c = getChar();

        while (c == ' ' || c == '\n' || c == '\r' || c == '\t') {
            c = getChar();
        }

        return c;
    }

    int readInt() {
        int c = skipSpaces();
        int x = 0;

        while ('0' <= c && c <= '9') {
            x = x * 10 + (c - '0');
            c = getChar();
        }

        return x;
    }

    void readWord(char *s) {
        int c = skipSpaces();
        int len = 0;

        while (c != EOF && c > ' ') {
            s[len++] = char(c);
            c = getChar();
        }

        s[len] = '\0';
    }

    const int OUT_BUF = 1 << 22;
    char outBuf[OUT_BUF];
    int outPos = 0;

    void flush() {
        fwrite(outBuf, 1, outPos, stdout);
        outPos = 0;
    }

    void putChar(char c) {
        if (outPos == OUT_BUF) {
            flush();
        }

        outBuf[outPos++] = c;
    }

    void putStr(const char *s) {
        while (*s) {
            putChar(*s++);
        }
    }

    void putInt(long long x) {
        if (x == 0) {
            putChar('0');
            return;
        }

        char tmp[24];
        int len = 0;

        while (x > 0) {
            tmp[len++] = char('0' + x % 10);
            x /= 10;
        }

        while (len > 0) {
            putChar(tmp[--len]);
        }
    }

    void putOrdinal(long long x) {
        putInt(x);
        putStr("th");
    }
}

/* ---------------- Command handling ---------------- */

void doPut(int x, int cubes) {
    /*
        If cell x is already occupied, the tower structure does not change.
    */
    if (heightArr[x] > 0) {
        heightArr[x] += cubes;

        int tower = predecessorNode(root, x);
        sumArr[tower] += cubes;

        return;
    }

    /*
        Cell x becomes occupied for the first time.
    */
    heightArr[x] = cubes;

    bool hasLeft = heightArr[x - 1] > 0;
    bool hasRight = heightArr[x + 1] > 0;

    if (!hasLeft && !hasRight) {
        /*
            New isolated tower [x, x].
        */
        int v = newNode(x, x, cubes);
        root = insertNode(root, v);
    } else if (hasLeft && !hasRight) {
        /*
            Extend the tower on the left.
        */
        int leftTower = predecessorNode(root, x - 1);

        rightEndArr[leftTower] = x;
        sumArr[leftTower] += cubes;
    } else if (!hasLeft && hasRight) {
        /*
            Extend the tower on the right to the left.

            The right tower starts at x + 1.
            We can safely change its key to x because x - 1 is empty,
            so BST order is preserved.
        */
        int rightTower = findNode(root, x + 1);

        keyArr[rightTower] = x;
        sumArr[rightTower] += cubes;
    } else {
        /*
            Merge left tower, cell x, and right tower.
        */
        int leftTower = predecessorNode(root, x - 1);
        int rightTower = findNode(root, x + 1);

        rightEndArr[leftTower] = rightEndArr[rightTower];
        sumArr[leftTower] += (long long)cubes + sumArr[rightTower];

        root = eraseNode(root, x + 1);
    }
}

int main() {
    int n = FastIO::readInt();

    char cmd[8];

    for (int i = 0; i < n; ++i) {
        FastIO::readWord(cmd);

        if (cmd[0] == 'p') {
            /*
                put x c
            */
            int x = FastIO::readInt();
            int c = FastIO::readInt();

            doPut(x, c);
        } else if (cmd[0] == 'c') {
            /*
                cubes t
            */
            int t = FastIO::readInt();
            int v = kthNode(root, t - 1);

            FastIO::putInt(sumArr[v]);
            FastIO::putStr(" cubes in ");
            FastIO::putOrdinal(t);
            FastIO::putStr(" tower\n");
        } else if (cmd[0] == 'l') {
            /*
                length t
            */
            int t = FastIO::readInt();
            int v = kthNode(root, t - 1);

            FastIO::putStr("length of ");
            FastIO::putOrdinal(t);
            FastIO::putStr(" tower is ");
            FastIO::putInt(rightEndArr[v] - keyArr[v] + 1);
            FastIO::putChar('\n');
        } else if (cmd[1] == 'o') {
            /*
                towers
            */
            FastIO::putInt(getSize(root));
            FastIO::putStr(" towers\n");
        } else if (cmd[1] == 'p') {
            /*
                tput t x c
            */
            int t = FastIO::readInt();
            int x = FastIO::readInt();
            int c = FastIO::readInt();

            int v = kthNode(root, t - 1);
            int cell = keyArr[v] + x - 1;

            heightArr[cell] += c;
            sumArr[v] += c;
        } else {
            /*
                tcubes t x
            */
            int t = FastIO::readInt();
            int x = FastIO::readInt();

            int v = kthNode(root, t - 1);
            int cell = keyArr[v] + x - 1;

            FastIO::putInt(heightArr[cell]);
            FastIO::putStr(" cubes in ");
            FastIO::putOrdinal(x);
            FastIO::putStr(" column of ");
            FastIO::putOrdinal(t);
            FastIO::putStr(" tower\n");
        }
    }

    FastIO::flush();

    return 0;
}
```

---

## 5. Python implementation with detailed comments

Python is included for clarity and education. The original limits are quite tight, so C++ is the safer choice for actual submission.

```python
import sys
from array import array

# ------------------------------------------------------------
# Fast scanner.
#
# We read the whole input once and parse tokens manually.
# This avoids creating a huge list with data.split().
# ------------------------------------------------------------

class FastScanner:
    def __init__(self):
        self.data = sys.stdin.buffer.read()
        self.i = 0
        self.n = len(self.data)

    def next_token(self):
        data = self.data
        n = self.n
        i = self.i

        while i < n and data[i] <= 32:
            i += 1

        j = i

        while j < n and data[j] > 32:
            j += 1

        self.i = j
        return data[i:j]

    def next_int(self):
        data = self.data
        n = self.n
        i = self.i

        while i < n and data[i] <= 32:
            i += 1

        x = 0

        while i < n and data[i] > 32:
            x = x * 10 + data[i] - 48
            i += 1

        self.i = i
        return x


# ------------------------------------------------------------
# Treap stored in arrays.
#
# Node index 0 means null.
#
# For node v:
#   key[v]   = left boundary of tower
#   end[v]   = right boundary of tower
#   sumv[v]  = total cubes in tower
#   left[v]  = left child
#   right[v] = right child
#   size[v]  = subtree size
#   prio[v]  = randomized priority
# ------------------------------------------------------------

key = array("i", [0])
end = array("i", [0])
sumv = array("q", [0])

left = array("i", [0])
right = array("i", [0])
size = array("i", [0])
prio = array("Q", [0])

# Deterministic 64-bit xorshift generator for treap priorities.
seed = 88172645463393265
MASK = (1 << 64) - 1


def rng():
    global seed

    seed ^= (seed << 7) & MASK
    seed ^= seed >> 9

    return seed & MASK


def new_node(l, r, s):
    """
    Create one treap node representing tower [l, r]
    with total cube count s.
    """
    idx = len(key)

    key.append(l)
    end.append(r)
    sumv.append(s)

    left.append(0)
    right.append(0)
    size.append(1)
    prio.append(rng())

    return idx


def pull(v):
    """
    Recalculate subtree size of node v.
    """
    size[v] = 1 + size[left[v]] + size[right[v]]


sys.setrecursionlimit(2_000_000)


def split(t, k):
    """
    Split treap t into two treaps:

    a: all nodes with key <= k
    b: all nodes with key > k
    """
    if t == 0:
        return 0, 0

    if k < key[t]:
        a, b = split(left[t], k)
        left[t] = b
        pull(t)
        return a, t
    else:
        a, b = split(right[t], k)
        right[t] = a
        pull(t)
        return t, b


def merge(a, b):
    """
    Merge two treaps.

    Requirement:
    every key in a must be <= every key in b.
    """
    if a == 0 or b == 0:
        return a or b

    if prio[a] > prio[b]:
        right[a] = merge(right[a], b)
        pull(a)
        return a
    else:
        left[b] = merge(a, left[b])
        pull(b)
        return b


def insert(t, v):
    """
    Insert node v into treap t.
    Return the new root.
    """
    if t == 0:
        return v

    if prio[v] > prio[t]:
        a, b = split(t, key[v])
        left[v] = a
        right[v] = b
        pull(v)
        return v

    if key[v] < key[t]:
        left[t] = insert(left[t], v)
    else:
        right[t] = insert(right[t], v)

    pull(t)
    return t


def erase(t, k):
    """
    Erase the node with exact key k.
    Return the new root.
    """
    if key[t] == k:
        return merge(left[t], right[t])

    if k < key[t]:
        left[t] = erase(left[t], k)
    else:
        right[t] = erase(right[t], k)

    pull(t)
    return t


def kth(t, k):
    """
    Return the node index of the zero-based k-th tower.
    """
    while t:
        left_size = size[left[t]]

        if k < left_size:
            t = left[t]
        elif k == left_size:
            return t
        else:
            k -= left_size + 1
            t = right[t]

    return 0


def find_node(t, k):
    """
    Find node with exact key k.
    """
    while t:
        if key[t] == k:
            return t

        if k < key[t]:
            t = left[t]
        else:
            t = right[t]

    return 0


def predecessor_node(t, x):
    """
    Find the node with the largest key <= x.
    """
    ans = 0

    while t:
        if key[t] <= x:
            ans = t
            t = right[t]
        else:
            t = left[t]

    return ans


# ------------------------------------------------------------
# Main solving logic.
# ------------------------------------------------------------

def main():
    scanner = FastScanner()

    n = scanner.next_int()

    # height[x] = number of cubes on global cell x.
    # Extra cells make x - 1 and x + 1 safe.
    height = array("i", [0]) * (1_000_000 + 2)

    root = 0

    # Buffered output.
    out = []
    out_size = 0
    write = sys.stdout.write

    def emit(s):
        """
        Append output line to buffer and flush occasionally.
        """
        nonlocal out_size

        out.append(s)
        out_size += len(s)

        if out_size >= (1 << 20):
            write("".join(out))
            out.clear()
            out_size = 0

    def ordinal(x):
        """
        Problem explicitly wants 1th, 2th, 3th, ...
        """
        return str(x) + "th"

    def do_put(x, c):
        """
        Handle command:
            put x c
        """
        nonlocal root

        # Cell already occupied: tower structure does not change.
        if height[x] > 0:
            height[x] += c

            v = predecessor_node(root, x)
            sumv[v] += c

            return

        # Cell becomes occupied.
        height[x] = c

        has_left = height[x - 1] > 0
        has_right = height[x + 1] > 0

        if not has_left and not has_right:
            # New isolated tower [x, x].
            root = insert(root, new_node(x, x, c))

        elif has_left and not has_right:
            # Extend the left tower to the right.
            lt = predecessor_node(root, x - 1)

            end[lt] = x
            sumv[lt] += c

        elif not has_left and has_right:
            # Extend the right tower to the left.
            rt = find_node(root, x + 1)

            # Safe because x - 1 is empty.
            key[rt] = x
            sumv[rt] += c

        else:
            # Merge left tower, new cell x, and right tower.
            lt = predecessor_node(root, x - 1)
            rt = find_node(root, x + 1)

            end[lt] = end[rt]
            sumv[lt] += c + sumv[rt]

            root = erase(root, x + 1)

    for _ in range(n):
        cmd = scanner.next_token()

        if cmd[0] == ord("p"):
            # put x c
            x = scanner.next_int()
            c = scanner.next_int()

            do_put(x, c)

        elif cmd[0] == ord("c"):
            # cubes t
            t = scanner.next_int()
            v = kth(root, t - 1)

            emit(f"{sumv[v]} cubes in {ordinal(t)} tower\n")

        elif cmd[0] == ord("l"):
            # length t
            t = scanner.next_int()
            v = kth(root, t - 1)

            length = end[v] - key[v] + 1

            emit(f"length of {ordinal(t)} tower is {length}\n")

        elif cmd[1] == ord("o"):
            # towers
            emit(f"{size[root]} towers\n")

        elif cmd[1] == ord("p"):
            # tput t x c
            t = scanner.next_int()
            x = scanner.next_int()
            c = scanner.next_int()

            v = kth(root, t - 1)
            cell = key[v] + x - 1

            height[cell] += c
            sumv[v] += c

        else:
            # tcubes t x
            t = scanner.next_int()
            x = scanner.next_int()

            v = kth(root, t - 1)
            cell = key[v] + x - 1

            emit(
                f"{height[cell]} cubes in "
                f"{ordinal(x)} column of "
                f"{ordinal(t)} tower\n"
            )

    if out:
        write("".join(out))


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