0w1

CFR 697 C. Lorenzo Von Matterhorn ( Tree Ad hoc )

Problem - C - Codeforces
Well, I came up with an algorithm to look at every previous operations in each operation, and splitting bifurcating paths into two unique paths. That gave me a TLE though I believe is good to go in terms of time complexity. Anyways, silly I did not figure out that having std::map to simply simulate will be fine, since there are only at most 64 * 1000 nodes to be used.

void solve(){
    int Q; cin >> Q;
    map< ll, ll > cost;
    while( Q-- ){
        int op; cin >> op;
        if( op == 1 ){
            ll u, v, w; cin >> u >> v >> w;
            while( u != v ){
                if( not ( u > v ) )
                    swap( u, v );
                cost[ u ] += w;
                u >>= 1LL;
            }
        } else{
            ll u, v; cin >> u >> v;
            ll ans = 0;
            while( u != v ){
                if( not ( u > v ) )
                    swap( u, v );
                if( cost.count( u ) )
                    ans += cost[ u ];
                u >>= 1;
            }
            cout << ans << "\n";
        }
    }
}
// TLE
vi int_to_bin( ll x ){
    vi res;
    stack< int > stk;
    while( x > 0 )
        stk.push( x & 1LL ),
        x >>= 1LL;
    while( not stk.empty() )
        res.push_back( stk.top() ),
        stk.pop();
    return res;
}

vi common_prefix( const vi &a, const vi &b ){
    vi res;
    for( int i = 0; i < a.size() and i < b.size(); ++i ){
        if( a[ i ] != b[ i ] ) return res;
        res.push_back( a[ i ] );
    }
    return res;
}

ll bin_to_int( const vi &v ){
    ll res = 0;
    for( int i = 0; i < v.size(); ++i )
        res = res * 2 + v[ i ];
    return res;
}

void show_bin( const vi &a ){
    for( int z : a )
        cout << z;
    cout << "\n";
}

void dfs( const vi &a, const vi &b, const vi &x, const vi &y, int &res, int k ){
    if( a == b ) return;
    if( x == y ) return;
    vi path = x; path.push_back( y[ x.size() ] );
    if( path.size() > b.size() ) return;
    if( path.size() <= a.size() ) return dfs( a, b, path, y, res, k );
    if( path.size() == a.size() and common_prefix( path, a ) != a ) return;
    while( k < path.size() ){
        if( path[ k ] != b[ k ] ) return;
        ++k;
    }
    dfs( a, b, path, y, ++res, k );
}

int get_count( const vi &a, const vi &b, const vi &x, const vi &y ){
    int res = 0;
    dfs( a, b, x, y, res, 0 );
    return res;
}

void solve(){
    int Q; cin >> Q;
    vector< tri > vop;
    for( int i = 0; i < Q; ++i ){
        int op; cin >> op;
        if( op == 1 ){
            ll u, v, w; cin >> u >> v >> w;
            if( not ( u < v ) ) swap( u, v );
            vi u_bin = int_to_bin( u );
            vi v_bin = int_to_bin( v );
            vi anc_bin = common_prefix( u_bin, v_bin );
            if( anc_bin != u_bin ) vop.push_back( tri( anc_bin, pair< vi, ll >( u_bin, w ) ) );
            if( anc_bin != v_bin ) vop.push_back( tri( anc_bin, pair< vi, ll >( v_bin, w ) ) );
        } else{
            ll u, v; cin >> u >> v;
            if( not ( u < v ) ) swap( u, v );
            vi u_bin = int_to_bin( u );
            vi v_bin = int_to_bin( v );
            vi anc_bin = common_prefix( u_bin, v_bin );
            ll res = 0;
            for( int j = 0; j < vop.size(); ++j ){
                vi x_bin = vop[ j ].tr1;
                vi y_bin = vop[ j ].tr2;
                vi z_bin = common_prefix( x_bin, y_bin );
                // show_bin( x_bin ), show_bin( y_bin ), show_bin( z_bin );
                int w = vop[ j ].tr3;
                res += 1LL * get_count( anc_bin, u_bin, z_bin, x_bin ) * w;
                res += 1LL * get_count( anc_bin, v_bin, z_bin, y_bin ) * w;
                res += 1LL * get_count( anc_bin, u_bin, z_bin, y_bin ) * w;
                res += 1LL * get_count( anc_bin, v_bin, z_bin, x_bin ) * w;
            }
            cout << res << "\n";
        }
    }
}