Problem:
Weighted Union Find Trees

There is a sequence $A = a_0, a_1, ..., a_{n-1}$. You are given the following information and questions.

relate$(x, y, z)$: $a_y$ is greater than $a_x$ by $z$

diff$(x, y)$: report the difference between $a_x$ and $a_y$ $(a_y - a_x)$

Input

$n \; q$
$query_1$
$query_2$
:
$query_q$

In the first line, $n$ and $q$ are given. Then, $q$ information/questions are given in the following format.

0 $x \; y\; z$

or

1 $x \; y$

where '0' of the first digit denotes the relate information and '1' denotes the diff question.

Output

For each diff question, print the difference between $a_x$ and $a_y$ $(a_y - a_x)$.

Constraints

$2 \leq n \leq 100,000$

$1 \leq q \leq 200,000$

$0 \leq x, y < n$

$x \ne y$

$0 \leq z \leq 10000$

There are no inconsistency in the given information

Sample Input

5 6
0 0 2 5
0 1 2 3
1 0 1
1 1 3
0 1 4 8
1 0 4

Sample Output

2
?
10

Solution in C (judge verdict: Accepted)

// AOJ DSL_1_B Weighted Union Find Trees
// 2018.4.28 bal4u

#include <stdio.h>

// <重み付きUnion Find>
#define MAX 100003

int par[MAX], ws[MAX];

void initWeightedUnionFind(int n)
{
	int i;
	for (i = 0; i < n; i++) par[i] = -1;
}

int find(int x)
{
	int p;
	if (par[x] < 0) return x;
    p = find(par[x]), ws[x] += ws[par[x]];
    return par[x] = p;
}
    
int weight(int x)
{
    find(x); 
    return ws[x];
}
    
int unite(int x, int y, int w)  // x <-(w)- y (x + w = y)
{
	int tmp;

    w += weight(x), w -= weight(y);
    x = find(x), y = find(y);
    if (x == y) return 0;
    if (par[y] < par[x]) // 多い方が根になるようにスワップする.
        tmp = x, x = y, y = tmp, w = -w;
    
    par[x] += par[y], par[y] = x;
    ws[y] = w;
    return 1;
}
    
int same(int x, int y)
{
	return find(x) == find(y);
}

// *ans = x - y. 比較不能なら return 0.
int diff(int *ans, int x, int y)
{
    if (find(x) != find(y)) return 0;
	*ans = ws[x] - ws[y];
	return 1;
}
// </重み付きUnion Find>

#define gc() getchar_unlocked()
int in()
{
	int n = 0, c = gc();
	do n = 10*n + (c & 0xf), c = gc();
	while (c >= '0');
	return n;
}

int main()
{
	int n, q, k, x, y, z;
	
	n = in(), q = in();
	initWeightedUnionFind(n);
	while (q--) {
		if (in()) {
			x = in(), y = in();
			z = diff(&k, x, y);
			if (!z) puts("?");
			else printf("%d\n", k);
		} else {
			x = in(), y = in(), z = in();
			unite(y, x, z);
		}
	}
	return 0;
}