// Weighted Union Find Trees

#include <iostream>

using namespace std;

int n, q;

int fat[100000];
int dis[100000];

int find(int u) {
	if (fat[u] == u)
		return u;
	int g = find(fat[u]);
	dis[u] += dis[fat[u]];
	fat[u] = g;
	return g;
}

void relate(int x, int y, int z) {
	int u = find(x);
	int v = find(y);
	fat[u] = v;
	dis[u] = z - dis[x] + dis[y];
}

bool check(int x, int y) {
	x = find(x);
	y = find(y);
	return x == y;
}

int diff(int x, int y) {
	find(x);
	find(y);
	return dis[x] - dis[y];
}

int main() {
	cin >> n >> q;
	for (int i = 0; i < n; ++i)
		fat[i] = i, dis[i] = 0;
	for (int i = 0; i < q; ++i) {
		int k, x, y, z;
		cin >> k >> x >> y;
		if (k == 0)
			cin >> z, relate(x, y, z);
		else {
			if (check(x, y))
				cout << diff(x, y) << endl;
			else
				cout << "?" << endl;
		}
	}
	return 0;
}
