This documentation is automatically generated by online-judge-tools/verification-helper
#define PROBLEM "https://onlinejudge.u-aizu.ac.jp/courses/library/3/DSL/1/DSL_1_B"
#include <iostream>
#include "C++/ds/uf/UFPotential.hpp"
int main() {
int n, q;
std::cin >> n >> q;
man::UFPotential uf(n);
while(q--) {
int t, x, y;
std::cin >> t >> x >> y;
if(t) {
if(uf[x] == uf[y]) {
std::cout << uf.dist(x, y) << '\n';
}
else {
std::cout << "?\n";
}
}
else {
int z;
std::cin >> z;
uf.unite(x, y, z);
}
}
}
#line 1 "test/ufpotential.test.cpp"
#define PROBLEM "https://onlinejudge.u-aizu.ac.jp/courses/library/3/DSL/1/DSL_1_B"
#include <iostream>
#line 2 "C++/ds/uf/UFPotential.hpp"
#include <vector>
namespace man {
struct UFPotential {
private:
std::vector<int> par;
std::vector<long long> diff;
public:
UFPotential(const int n): par(n, -1), diff(n){}
inline int root(const int i) noexcept {
if(par[i] < 0) {
return i;
}
const int r = root(par[i]);
diff[i] += diff[par[i]];
return par[i] = r;
}
inline int dist(const int i) noexcept {
root(i);
return diff[i];
}
inline long long dist(const int x, const int y) noexcept { return dist(y) - dist(x); }
inline int unite(int x, int y, long long w) noexcept {
w += dist(y, x);
x = root(x), y = root(y);
if(x == y) {
return w == 0 ? 0 : -1;
}
if(par[x] > par[y]) {
std::swap(x, y);
w = -w;
}
par[x] += par[y];
par[y] = x;
diff[y] = w;
return 1;
}
inline int operator[](const int i) noexcept { return root(i); }
};
}
/**
* @brief ポテンシャル付きUnionFind
* @see https://github.com/tatyam-prime/kyopro_library/blob/master/UnionFind.cpp
*/
#line 4 "test/ufpotential.test.cpp"
int main() {
int n, q;
std::cin >> n >> q;
man::UFPotential uf(n);
while(q--) {
int t, x, y;
std::cin >> t >> x >> y;
if(t) {
if(uf[x] == uf[y]) {
std::cout << uf.dist(x, y) << '\n';
}
else {
std::cout << "?\n";
}
}
else {
int z;
std::cin >> z;
uf.unite(x, y, z);
}
}
}