#include<bits/stdc++.h>
using namespace std;
using ll = long long;

template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return 1; } return 0; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return 1; } return 0; }

#define FOR(i,a,b) for(ll i=(a);i<(b);++i)
#define ALL(v) (v).begin(), (v).end()
#define p(s) cout<<(s)<<endl
#define p2(s, t) cout << (s) << " " << (t) << endl
#define br() p("")
#define pn(s) cout << (#s) << " " << (s) << endl
#define p_yes() p("Yes")
#define p_no() p("No")

const ll mod = 1e9 + 7;
const ll inf = 1e18;

template < typename T >
void vprint(T &V){
	for(auto v : V){
    	cout << v << " ";
	}
	cout << endl;
}

struct WeightedUnionFind{
    vector<ll> par;
    vector<ll> rank;
    vector<ll> diff_weight;

    WeightedUnionFind(ll sz){
        init(sz);
    }

    void init(ll sz){
        par.resize(sz);
        rank.resize(sz);
        diff_weight.resize(sz);
        FOR(i, 0, sz){
            par[i] = i;
            rank[i] = 0;
            diff_weight[i] = 0;
        }
    }

    int root(ll x) {
        if (par[x] == x) {
            return x;
        }
        else {
            ll r = root(par[x]);
            diff_weight[x] += diff_weight[par[x]];
            return par[x] = r;
        }
    }

    ll weight(ll x) {
        root(x);
        return diff_weight[x];
    }

    bool is_same(ll x, ll y) {
        return root(x) == root(y);
    }

    bool merge(ll x, ll y, ll w) {
        w += weight(x); w -= weight(y);
        x = root(x); y = root(y);
        if (x == y) return false;
        if (rank[x] < rank[y]) swap(x, y), w = -w;
        if (rank[x] == rank[y]) ++rank[x];
        par[y] = x;
        diff_weight[y] = w;
        return true;
    }

    ll diff(int x, int y) {
        return weight(y) - weight(x);
    }
};


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

    // input
    ll N, Q;
    cin >> N >> Q;

    auto uf = WeightedUnionFind(N);

    while(Q--){
        ll a; cin >> a;
        // diff
        if(a){
            ll x, y; cin >> x >> y;
            if(uf.is_same(x, y)){
                p(uf.diff(x, y));
            }else{
                p('?');
            }
        }
        // relate
        else{
            ll x, y, z; cin >> x >> y >> z;
            uf.merge(x, y, z);
        }
    }
    
    return 0;
}
