/+ dub.sdl:
    name "A"
    dependency "dcomp" version=">=0.0.2"
+/

import std.algorithm, std.range, std.stdio, std.math, std.conv, core.bitop;

// import dcomp.scanner;
// import dcomp.algorithm;
// import dcomp.array;
// import dcomp.memory;

struct Edge {
    int to;
    long dist;
}
Edge[][] g;
long md;

long[2][] dfs(int p) {
    if (g[p].empty) {
        static auto leaf = [[0L, 0L].toStaticArray];
        return leaf;
    }
    Edge le = g[p][0], re = g[p][1];
    auto lt = dfs(le.to);
    auto rt = dfs(re.to);
    if (lt.length > rt.length) {
        swap(le, re);
        swap(lt, rt);
    }
    long ld = le.dist, rd = re.dist;
    auto buf = FastAppender!(long[2][], true)();
    buf.reserve(2*lt.length);
    foreach (co; lt) {
        //co[1] + ld + rd + rco[0] <= md
        int idx = binSearch!((i){return co[1]+ld+rd+rt[i][0] > md;})(-1, rt.length.to!int)-1;
        if (idx == -1) continue;
        buf ~= [co[0]+ld, rt[idx][1]+rd];
        buf ~= [rt[idx][1]+rd, co[0]+ld];
    }
    auto ans = buf.data;
    sort!cmpStaticArray(ans);
    if (ans.empty) return ans;
    long ma = 10L^^15;
    int co = 0;
    foreach (e; ans) {
        if (ma <= e[1]) {
            continue;
        }
        ma = min(ma, e[1]);
        ans[co] = e;
        co++;
    }
 
    return ans[0..co];
}
 
//md以下にできるか？
bool solve(long _md) {
    md = _md;
    nowPool.allFree;
    return !dfs(0).empty;
}
 
int main(string[] argv) {
    import std.c.stdio;
    int n;
    scanf("%d", &n);
    g = new Edge[][](n);
    foreach (i; 1..n) {
        int a; long b;
        scanf("%d %lld", &a, &b); a--;
        g[a] ~= Edge(i, b);
    }
    nowPool = new MemoryPool(2^^22);
    writeln(binSearch!solve(-1L, 10L^^12));
    return 0;
}
/* IMPORT /Users/yosupo/Program/dcomp/source/dcomp/array.d */
// module dcomp.array;

// import dcomp.memory;

struct FastAppender(A, bool useMyPool = false) {
    @disable this(this);

    import std.algorithm : max;
    import std.range.primitives : ElementEncodingType;
    import core.stdc.string : memcpy;

    private alias T = ElementEncodingType!A;
    private T* _data;
    private size_t len, cap;

    this(T[]* arr) {
        _data = (*arr).ptr;
        len = (*arr).length;
        cap = (*arr).length;
    }
    void reserve(size_t nlen) {
        import core.memory : GC;
        if (nlen <= cap) return;

        void* nx;
        if (useMyPool) {
            nx = nowPool.malloc(nlen * T.sizeof);
        } else {
            nx = GC.malloc(nlen * T.sizeof, GC.BlkAttr.NO_SCAN | GC.BlkAttr.APPENDABLE);
        }
        cap = nlen;
        if (len) memcpy(nx, _data, len * T.sizeof);
        _data = cast(T*)(nx);
    }
    void opOpAssign(string op : "~")(T item) {
        if (len == cap) {
            reserve(max(4, cap*2));
        }
        _data[len++] = item;
    }
    void clear() {
        len = 0;
    }
    T[] data() {
        return (_data) ? _data[0..len] : null;
    }
}

T[N] toStaticArray(T, int N)(T[N] a) {return a;}
bool cmpStaticArray(T, int N)(in T[N] a, in T[N] b) {
    foreach (i; 0..N) {
        if (a[i] != b[i]) return a[i] < b[i];
    }
    return false;
}

/* IMPORT /Users/yosupo/Program/dcomp/source/dcomp/scanner.d */
// module dcomp.scanner;

class Scanner {
    import std.stdio : File, stdin;
    import std.conv : to;
    import std.range : front, popFront, array, ElementType;
    import std.array : split;
    import std.traits : isSomeString, isDynamicArray;
    import std.algorithm : map;
    File f;
    this(File f = stdin) {
        this.f = f;
    }
    string[] buf;
    bool succ() {
        while (!buf.length) {
            if (f.eof) return false;
            buf = f.readln.split;
        }
        return true;
    }
    int read(Args...)(auto ref Args args) {
        foreach (i, ref v; args) {
            if (!succ()) return i;
            alias VT = typeof(v);
            static if (!isSomeString!VT && isDynamicArray!VT) {
                v = buf.map!(to!(ElementType!VT)).array;
                buf.length = 0;
            } else {
                v = buf.front.to!VT;
                buf.popFront();
            }
        }
        return args.length;
    }
}
/* IMPORT /Users/yosupo/Program/dcomp/source/dcomp/memory.d */
// module dcomp.memory;

MemoryPool _nowPool;

@property void nowPool(MemoryPool newPool) {
    _nowPool = newPool;
}
@property MemoryPool nowPool() {
    return _nowPool;
}

class MemoryPool {
    import core.memory : GC;
    import std.algorithm : max;

    static immutable Allign = 16;
    GC.BlkInfo[] blks;
    size_t e, idx, pos;
    this(size_t e) {
        this.e = e;
        idx = pos = 0;
    }
    void assign(size_t sz) {
        blks ~= GC.qalloc(sz);
    }
    void* malloc(size_t sz) {   
        sz = (sz + Allign-1) / Allign * Allign;
        while (idx < blks.length && blks[idx].size < pos + sz) {
            idx++; pos = 0;
        }

        if (idx == blks.length) {
            assign(max(e, sz)); pos = 0;
        }
        pos += sz;
        assert(pos <= blks[idx].size);
        return cast(void *)(cast(byte *)(blks[idx].base) + pos - sz);
    }
    void allFree() {
        idx = pos = 0;
    }
}
/* IMPORT /Users/yosupo/Program/dcomp/source/dcomp/algorithm.d */
// module dcomp.algorithm;

//[0,0,0,...,1,1,1]で、初めて1となる場所を探す。pred(l) == 0, pred(r) == 1と仮定
T binSearch(alias pred, T)(T l, T r) {
    while (r-l > 1) {
        T md = (l+r)/2;
        if (!pred(md)) l = md;
        else r = md;
    }
    return r;
}


Measured memory_bytes: 24828