Gold Transfer
You are given a rooted tree. Each vertex contains $$$a_i$$$ tons of gold, which costs $$$c_i$$$ per one ton. Initially, the tree consists only a root numbered $$$0$$$ with $$$a_0$$$ tons of gold and price $$$c_0$$$ per ton.There are $$$q$$$ queries. Each query has one of two types:   Add vertex $$$i$$$ (where $$$i$$$ is an index of query) as a son to some vertex $$$p_i$$$; vertex $$$i$$$ will have $$$a_i$$$ tons of gold with $$$c_i$$$ per ton. It's guaranteed that $$$c_i > c_{p_i}$$$.  For a given vertex $$$v_i$$$ consider the simple path from $$$v_i$$$ to the root. We need to purchase $$$w_i$$$ tons of gold from vertices on this path, spending the minimum amount of money. If there isn't enough gold on the path, we buy all we can. If we buy $$$x$$$ tons of gold in some vertex $$$v$$$ the remaining amount of gold in it decreases by $$$x$$$ (of course, we can't buy more gold that vertex has at the moment). For each query of the second type, calculate the resulting amount of gold we bought and the amount of money we should spend.Note that you should solve the problem in online mode. It means that you can't read the whole input at once. You can read each query only after writing the answer for the last query, so don't forget to flush output after printing answers. You can use functions like fflush(stdout) in C++ and BufferedWriter.flush in Java or similar after each writing in your program. In standard (if you don't tweak I/O), endl flushes cout in C++ and System.out.println in Java (or println in Kotlin) makes automatic flush as well. 
Explanation of the sample:At the first query, the tree consist of root, so we purchase $$$2$$$ tons of gold and pay $$$2 \cdot 2 = 4$$$. $$$3$$$ tons remain in the root.At the second query, we add vertex $$$2$$$ as a son of vertex $$$0$$$. Vertex $$$2$$$ now has $$$3$$$ tons of gold with price $$$4$$$ per one ton.At the third query, a path from $$$2$$$ to $$$0$$$ consists of only vertices $$$0$$$ and $$$2$$$ and since $$$c_0 < c_2$$$ we buy $$$3$$$ remaining tons of gold in vertex $$$0$$$ and $$$1$$$ ton in vertex $$$2$$$. So we bought $$$3 + 1 = 4$$$ tons and paid $$$3 \cdot 2 + 1 \cdot 4 = 10$$$. Now, in vertex $$$0$$$ no gold left and $$$2$$$ tons of gold remain in vertex $$$2$$$.At the fourth query, we add vertex $$$4$$$ as a son of vertex $$$0$$$. Vertex $$$4$$$ now has $$$1$$$ ton of gold with price $$$3$$$.At the fifth query, a path from $$$4$$$ to $$$0$$$ consists of only vertices $$$0$$$ and $$$4$$$. But since no gold left in vertex $$$0$$$ and only $$$1$$$ ton is in vertex $$$4$$$, we buy $$$1$$$ ton of gold in vertex $$$4$$$ and spend $$$1 \cdot 3 = 3$$$. Now, in vertex $$$4$$$ no gold left.
The first line contains three integers $$$q$$$, $$$a_0$$$ and $$$c_0$$$ ($$$1 \le q \le 3 \cdot 10^5$$$; $$$1 \le a_0, c_0 < 10^6$$$) — the number of queries, the amount of gold in the root and its price.Next $$$q$$$ lines contain descriptions of queries; The $$$i$$$-th query has one of two types:   "$$$1$$$ $$$p_i$$$ $$$a_i$$$ $$$c_i$$$" ($$$0 \le p_i < i$$$; $$$1 \le a_i, c_i < 10^6$$$): add vertex $$$i$$$ as a son to vertex $$$p_i$$$. The vertex $$$i$$$ will have $$$a_i$$$ tons of gold with price $$$c_i$$$ per one ton. It's guaranteed that $$$p_i$$$ exists and $$$c_i > c_{p_i}$$$. "$$$2$$$ $$$v_i$$$ $$$w_i$$$" ($$$0 \le v_i < i$$$; $$$1 \le w_i < 10^6$$$): buy $$$w_i$$$ tons of gold from vertices on path from $$$v_i$$$ to $$$0$$$ spending the minimum amount of money. If there isn't enough gold, we buy as much as we can. It's guaranteed that vertex $$$v_i$$$ exist. It's guaranteed that there is at least one query of the second type.
For each query of the second type, print the resulting amount of gold we bought and the minimum amount of money we should spend.
import os
ii = 0
_inp = b''

def getchar():
    global ii, _inp
    if ii >= len(_inp):
        _inp = os.read(0, 4096)
        ii = 0
    if not _inp:
        return b' '[0]
    ii += 1
    return _inp[ii - 1]

def input():
    c = getchar()
    if c == b'-'[0]:
        x = 0
        sign = 1
    else:
        x = c - b'0'[0]
        sign = 0
    c = getchar()
    while c >= b'0'[0]:
        x = 10 * x + c - b'0'[0]
        c = getchar()
    if c == b'\r'[0]:
        getchar()
    return -x if sign else x

def main():
    (Q, A0, C0) = (int(input()), int(input()), int(input()))
    N = Q + 2
    A = [0] * N
    C = [0] * N
    P = [0] * N
    pref = [0] * N
    anc = [None for i in range(N)]
    anc[-1] = [-1] * 20
    root = 0
    A[root] = A0
    C[root] = C0
    P[root] = -1
    pref[root] = A0
    anc[root] = [-1] * 20

    def buildJumps(u, parent):
        jumps = [0] * 20
        jumps[0] = parent
        for i in range(1, 20):
            jumps[i] = anc[jumps[i - 1]][i - 1]
        anc[u] = jumps

    def getAncestor(u, k):
        for i in reversed(range(20)):
            if k & 1 << i:
                u = anc[u][i]
        return u

    def getLast(u, f):
        for i in reversed(range(20)):
            if f(anc[u][i]):
                u = anc[u][i]
        return u
    for i in range(1, Q + 1):
        kind = int(input())
        if kind == 1:
            (p, A[i], C[i]) = (int(input()), int(input()), int(input()))
            P[i] = p
            pref[i] = pref[p] + A[i]
            buildJumps(i, p)
        else:
            (v, want) = (int(input()), int(input()))
            gold = 0
            spend = 0
            if False:
                if A[v] != 0:
                    hi = getLast(v, lambda node: A[node])
                    target = want + (pref[hi] - A[hi])
                    lo = getLast(v, lambda node: pref[node] >= target)
                    path = [lo]
                    while path[-1] != hi:
                        path.append(P[path[-1]])
                    for u in reversed(path):
                        take = min(want, A[u])
                        A[u] -= take
                        gold += take
                        spend += C[u] * take
                        want -= take
            else:
                while A[v] != 0 and want:
                    u = getLast(v, lambda node: A[node] != 0)
                    take = min(want, A[u])
                    A[u] -= take
                    gold += take
                    spend += C[u] * take
                    want -= take
            os.write(1, b'%d %d\n' % (gold, spend))
if __name__ == '__main__':
    main()
import os, sys
input = sys.stdin.buffer.readline

def main():
    (Q, A0, C0) = [int(x) for x in input().split()]
    N = Q + 2
    A = [0] * N
    C = [0] * N
    P = [0] * N
    pref = [0] * N
    anc = [None for i in range(N)]
    anc[-1] = [-1] * 20
    root = 0
    A[root] = A0
    C[root] = C0
    P[root] = -1
    pref[root] = A0
    anc[root] = [-1] * 20

    def buildJumps(u, parent):
        jumps = [0] * 20
        jumps[0] = parent
        for i in range(1, 20):
            jumps[i] = anc[jumps[i - 1]][i - 1]
        anc[u] = jumps

    def getAncestor(u, k):
        for i in reversed(range(20)):
            if k & 1 << i:
                u = anc[u][i]
        return u

    def getLast(u, f):
        for i in reversed(range(20)):
            if f(anc[u][i]):
                u = anc[u][i]
        return u
    for i in range(1, Q + 1):
        query = [int(x) for x in input().split()]
        if query[0] == 1:
            (_, p, A[i], C[i]) = query
            P[i] = p
            pref[i] = pref[p] + A[i]
            buildJumps(i, p)
        else:
            assert query[0] == 2
            (_, v, want) = query
            gold = 0
            spend = 0
            if True:
                if A[v] != 0:
                    hi = getLast(v, lambda node: A[node])
                    target = want + (pref[hi] - A[hi])
                    lo = getLast(v, lambda node: pref[node] >= target)
                    path = [lo]
                    while path[-1] != hi:
                        path.append(P[path[-1]])
                    for u in reversed(path):
                        take = min(want, A[u])
                        A[u] -= take
                        gold += take
                        spend += C[u] * take
                        want -= take
            else:
                while A[v] != 0 and want:
                    u = getLast(v, lambda node: A[node] != 0)
                    take = min(want, A[u])
                    A[u] -= take
                    gold += take
                    spend += C[u] * take
                    want -= take
            os.write(1, b'%d %d\n' % (gold, spend))
if __name__ == '__main__':
    main()
import os
import sys
input = sys.stdin.buffer.readline

def main():
    (Q, A0, C0) = [int(x) for x in input().split()]
    N = Q + 2
    A = [0] * N
    C = [0] * N
    P = [0] * N
    pref = [0] * N
    anc = [None for i in range(N)]
    anc[-1] = [-1] * 20
    root = 0
    A[root] = A0
    C[root] = C0
    P[root] = -1
    pref[root] = A0
    anc[root] = [-1] * 20

    def buildJumps(u, parent):
        jumps = [0] * 20
        jumps[0] = parent
        for i in range(1, 20):
            jumps[i] = anc[jumps[i - 1]][i - 1]
        anc[u] = jumps

    def getAncestor(u, k):
        for i in reversed(range(20)):
            if k & 1 << i:
                u = anc[u][i]
        return u

    def getLast(u, f):
        for i in reversed(range(20)):
            if f(anc[u][i]):
                u = anc[u][i]
        return u
    for i in range(1, Q + 1):
        query = [int(x) for x in input().split()]
        if query[0] == 1:
            (_, p, A[i], C[i]) = query
            P[i] = p
            pref[i] = pref[p] + A[i]
            buildJumps(i, p)
        else:
            assert query[0] == 2
            (_, v, want) = query
            gold = 0
            spend = 0
            if False:
                if A[v] != 0:
                    hi = getLast(v, lambda node: A[node])
                    target = want + (pref[hi] - A[hi])
                    lo = getLast(v, lambda node: pref[node] >= target)
                    path = [lo]
                    while path[-1] != hi:
                        path.append(P[path[-1]])
                    for u in reversed(path):
                        take = min(want, A[u])
                        A[u] -= take
                        gold += take
                        spend += C[u] * take
                        want -= take
            else:
                while A[v] != 0 and want:
                    u = getLast(v, lambda node: A[node] != 0)
                    take = min(want, A[u])
                    A[u] -= take
                    gold += take
                    spend += C[u] * take
                    want -= take
            os.write(1, b'%d %d\n' % (gold, spend))
if __name__ == '__main__':
    main()