t = int(input())
for i in range(t):
    x1, y1, x2, y2 = map(int, input().split())
    if x1 == x2 or y1 == y2:
        print(1)
    else:
        print(4)


t = int(input())
for i in range(t):
    time = 0
    x1, y1, x2, y2 = map(int, input().split())
    if x1 == x2:
        print(y2-y1)
    elif y1 == y2:
        print(x2-x1)
    else:
        print(y2-y1+2+x2-x1)


t = int(input())
for i in range(t):
    time = 0
    x1, y1, x2, y2 = map(int, input().split())
    if x1 == x2:
        print(abs(y2-y1))
    elif y1 == y2:
        print(abs(x2-x1))
    else:
        print(abs(y2-y1)+2+abs(x2-x1))


t = int(input())
for T in range(t):
    a, b, c, d = map(int, input().split())
    ans = abs(a-c) + abs(b-d)
    if a!=c and b!=d:
        ans+=2

    print(ans)


t = int(input())
for T in range(t):
    a, b, c, d = map(int, input().split())
    ans = abs(a-c) + abs(b-d)
    if a!=c and b!=d:
        ans+=2

    print(ans


t = int(input())
for _ in range(t):
    x1,y1,x2,y2 = input().split()
    x1,y1,x2,y2 = int(x1),int(y1),int(x2),int(y2)
    xdiff = abs(x2 - x1)
    ydiff = abs(y2 -y1)
    if xdiff==0 and ydiff==0:
        print(0)
    elif xdiff==0 or ydiff==0:
        print(max(xdiff,ydiff))
    else:
        print(max(xdiff,ydiff)+min(xdiff,ydiff)-1+3)


t = int(input())
for _ in range(t):
    x1,y1,x2,y2 = input().split()
    x1,y1,x2,y2 = int(x1),int(y1),int(x2),int(y2)
    xdiff = abs(x2 - x1)
    ydiff = abs(y2 -y1)
    if xdiff==0 and ydiff==0:
        print(0)
    elif xdiff==0 or ydiff==0:
        print(1)
    else:
        print(min(xdiff,ydiff)+3)


t = int(input())
for _ in range(t):
    x1,y1,x2,y2 = input().split()
    x1,y1,x2,y2 = int(x1),int(y1),int(x2),int(y2)
    xdiff = abs(x2 - x1)
    ydiff = abs(y2 -y1)
    if xdiff==0 or ydiff==0:
        print(1)
    else:
        print(min(xdiff,ydiff)+3)


t = int(input())
for _ in range(t):
    x1,y1,x2,y2 = input().split()
    x1,y1,x2,y2 = int(x1),int(y1),int(x2),int(y2)
    xdiff = abs(x2 - x1)
    ydiff = abs(y2 -y1)
    if xdiff==0 and ydiff==0:
        print(0)
    elif xdiff==0 or ydiff==0:
        print(1)
    else:
        print(max(xdiff,ydiff)+min(xdiff,ydiff)-1+3)


import sys
# import numpy as np
############ ---- Input Functions ---- ############
def take_int(line):
    return(int(line))

def take_strings(line):
    return(list(line.split()))

def take_character_list(line):
    return(list(line[:len(line) - 1]))

def take_int_list(line):
    return(list(map(int,line.split())))

def move_time(x1, y1, x2, y2):
    return int(abs(x1-x2) + abs(y1-y2))

def cal_time(x1, y1, x2, y2):
    if x1 == x2 and y1 == y2:
        return 0, None
    elif (x1, y1) == (x2 + 1, y2):
        return 1, x2 + 1, y2
    elif (x1, y1) == (x2, y2 + 1):
         return 1, x2, y2 + 2
    elif (x1, y1) == (x2 - 1, y2):
        return 1, x2-2, y2
    elif (x1, y1) == (x2, y2 - 1):
        return 1, x2, y2 - 2
    elif x1 == x2:
        return abs(y2-y1), None
    elif y1 == y2:
        return abs(x2 - x1), None
    else:
        # iterlst = [cal_time(x1, y1, x2, y2-1), cal_time(x1, y1, x2, y2+1), cal_time(x1, y1, x2-1, y2), cal_time(x1, y1, x2+1, y2)]
        # ans = np.inf
        # pos = None
        # diff = None
        # for item in iterlst:
        #     curr = item[0] + move_time(item[1], item[2], x2, y2)
        #     if curr < ans:
        #         ans = curr
        #         diff = item[1] - x2, item[2] - y2
        # return ans, x2 + 2* diff[0], y2 + 2 * diff[1]
        return abs(y2-y1) + abs(x2-x1) + 2, None

if __name__ == "__main__":

    i = 0
    n = 0
    lst = []
    for line in sys.stdin:
        if i == 0:
            n = take_int(line)
        else:
            lst.append(take_int_list(line))
        i += 1

    for sublst in lst:
        # print(sublst)
        print(cal_time(sublst[0], sublst[1], sublst[2], sublst[3]) [0])


import sys
import numpy as np
############ ---- Input Functions ---- ############
def take_int(line):
    return(int(line))

def take_strings(line):
    return(list(line.split()))

def take_character_list(line):
    return(list(line[:len(line) - 1]))

def take_int_list(line):
    return(list(map(int,line.split())))

def move_time(x1, y1, x2, y2):
    return int(np.abs(x1-x2) + np.abs(y1-y2))

def cal_time(x1, y1, x2, y2):
    if x1 == x2 and y1 == y2:
        return 0, None
    elif (x1, y1) == (x2 + 1, y2):
        return 1, x2 + 1, y2
    elif (x1, y1) == (x2, y2 + 1):
         return 1, x2, y2 + 2
    elif (x1, y1) == (x2 - 1, y2):
        return 1, x2-2, y2
    elif (x1, y1) == (x2, y2 - 1):
        return 1, x2, y2 - 2
    elif x1 == x2:
        return np.abs(y2-y1), None
    elif y1 == y2:
        return np.abs(x2 - x1), None
    else:
        # iterlst = [cal_time(x1, y1, x2, y2-1), cal_time(x1, y1, x2, y2+1), cal_time(x1, y1, x2-1, y2), cal_time(x1, y1, x2+1, y2)]
        # ans = np.inf
        # pos = None
        # diff = None
        # for item in iterlst:
        #     curr = item[0] + move_time(item[1], item[2], x2, y2)
        #     if curr < ans:
        #         ans = curr
        #         diff = item[1] - x2, item[2] - y2
        # return ans, x2 + 2* diff[0], y2 + 2 * diff[1]
        return np.abs(y2-y1) + np.abs(x2-x1) + 2, None

if __name__ == "__main__":

    i = 0
    n = 0
    lst = []
    for line in sys.stdin:
        if i == 0:
            n = take_int(line)
        else:
            lst.append(take_int_list(line))
        i += 1

    for sublst in lst:
        # print(sublst)
        print(cal_time(sublst[0], sublst[1], sublst[2], sublst[3]) [0])


import sys
input = sys.stdin
import numpy as np
############ ---- Input Functions ---- ############
def take_int(line):
    return(int(line))

def take_strings(line):
    return(list(line.split()))

def take_character_list(line):
    return(list(line[:len(line) - 1]))

def take_int_list(line):
    return(list(map(int,line.split())))

def move_time(x1, y1, x2, y2):
    return int(np.abs(x1-x2) + np.abs(y1-y2))

def cal_time(x1, y1, x2, y2):
    if x1 == x2 and y1 == y2:
        return 0, None
    elif (x1, y1) == (x2 + 1, y2):
        return 1, x2 + 1, y2
    elif (x1, y1) == (x2, y2 + 1):
         return 1, x2, y2 + 2
    elif (x1, y1) == (x2 - 1, y2):
        return 1, x2-2, y2
    elif (x1, y1) == (x2, y2 - 1):
        return 1, x2, y2 - 2
    elif x1 == x2:
        return np.abs(y2-y1), None
    elif y1 == y2:
        return np.abs(x2 - x1), None
    else:
        # iterlst = [cal_time(x1, y1, x2, y2-1), cal_time(x1, y1, x2, y2+1), cal_time(x1, y1, x2-1, y2), cal_time(x1, y1, x2+1, y2)]
        # ans = np.inf
        # pos = None
        # diff = None
        # for item in iterlst:
        #     curr = item[0] + move_time(item[1], item[2], x2, y2)
        #     if curr < ans:
        #         ans = curr
        #         diff = item[1] - x2, item[2] - y2
        # return ans, x2 + 2* diff[0], y2 + 2 * diff[1]
        return np.abs(y2-y1) + np.abs(x2-x1) + 2, None

if __name__ == "__main__":

    i = 0
    n = 0
    lst = []
    for line in input:
        if i == 0:
            n = take_int(line)
        else:
            lst.append(take_int_list(line))
        i += 1

    for sublst in lst:
        # print(sublst)
        print(cal_time(sublst[0], sublst[1], sublst[2], sublst[3]) [0])


import sys
input = sys.stdin
import numpy as np
############ ---- Input Functions ---- ############
def take_int(line):
    return(int(line))

def take_strings(line):
    return(list(line.split()))

def take_character_list(line):
    return(list(line[:len(line) - 1]))

def take_int_list(line):
    return(list(map(int,line.split())))

def move_time(x1, y1, x2, y2):
    return int(np.abs(x1-x2) + np.abs(y1-y2))

def cal_time(x1, y1, x2, y2):
    if x1 == x2 and y1 == y2:
        return 0, None
    elif (x1, y1) == (x2 + 1, y2):
        return 1, x2 + 1, y2
    elif (x1, y1) == (x2, y2 + 1):
         return 1, x2, y2 + 2
    elif (x1, y1) == (x2 - 1, y2):
        return 1, x2-2, y2
    elif (x1, y1) == (x2, y2 - 1):
        return 1, x2, y2 - 2
    elif x1 == x2:
        return np.abs(y2-y1), None
    elif y1 == y2:
        return np.abs(x2 - x1), None
    else:
        # iterlst = [cal_time(x1, y1, x2, y2-1), cal_time(x1, y1, x2, y2+1), cal_time(x1, y1, x2-1, y2), cal_time(x1, y1, x2+1, y2)]
        # ans = np.inf
        # pos = None
        # diff = None
        # for item in iterlst:
        #     curr = item[0] + move_time(item[1], item[2], x2, y2)
        #     if curr < ans:
        #         ans = curr
        #         diff = item[1] - x2, item[2] - y2
        # return ans, x2 + 2* diff[0], y2 + 2 * diff[1]
        return np.abs(y2-y1) + np.abs(x2-x1) + 2, None

i = 0
n = 0
lst = []
for line in input:
    if i == 0:
        n = take_int(line)
    else:
        lst.append(take_int_list(line))
    i += 1

for sublst in lst:
    # print(sublst)
    print(cal_time(sublst[0], sublst[1], sublst[2], sublst[3]) [0])


#include<iostream>
#include<bits/stdc++.h>
using namespace std;
int main(){
    long m=pow(10,9)+7;
   int t;
   cin>>t;
   for(int i=0;i<t;i++){
       unsigned long long x1,y1,x2,y2;
       cin>>x1>>y1>>x2>>y2;
       if(x1==x2||y1==y2){
           cout<<fabs(x2-x1)+fabs(y2-y1)<<endl;
       }
       else{
           cout<<fabs(x2-x1)+fabs(y2-y1)+2<<endl;
       }
   }
}


t=int(input())
for i in range(t):
    l=list(map(int,input(),split()))
    if l[0]==l[2]:
        print(abs(l[1]-l[3]))
    elif l[1]==l[3]:
        print(abs(l[0]-l[2]))
    else:
        print(abs(l[1]-l[3]+abs(l[0]-l[2])+2))


t=int(input())
for i in range(t):
    l=list(map(int,input().split()))
    if l[0]==l[2]:
        print(abs(l[1]-l[3]))
    elif l[1]==l[3]:
        print(abs(l[0]-l[2]))
    else:
        print(abs(l[1]-l[3])+abs(l[0]-l[2])+2)


for i in range(int(input())):
    a,b,c,d = list(map(int,input().split()))
    if a<=c and b<=d:
        if a==c:
            print(d-b)
        elif b==d:
            print(c-a)
        else:
            print((c-a)+(d-b)+2)
    else:
        if a==c:
            print(b-d)
        elif b==d:
            print(a-c)
        else:
            print((a-c)+(b-d)+2)


for i in range(int(input())):
    a,b,c,d = list(map(int,input().split()))
    if a==c:
        print(max(d,b)-min(d,b))
    elif b==d:
        print(max(a,c)-min(a,c))
    else:
        print((max(d,b)-min(d,b))+(max(a,c)-min(a,c))+2)
    # else:
    #     if a==c:
    #         print(b-d)
    #     elif b==d:
    #         print(a-c)
    #     else:
    #         print((a-c)+(b-d)+2)

#
# for i in range(int(input())):
#     li = list(map(int,input().split()))
#     li.sort()
#


a = int(input())
for x in range(a):
    b,c,d,e = map(int,input().split())
    f = (abs(d-b)+abs(e-c))
    if d!=b and c!=e:
        f += 2
    print(f)


a = int(input())
for x in range(a):
    b,c,d,e = map(int,input().split())
    f = (abs(d-b)+abs(e-c))
    if d!=b and d!=e:
        f += 1
    print(f)


a = int(input())
for x in range(a):
    b,c,d,e = map(int,input().split())
    print((abs(d-b)+abs(e-c))**2)


a = int(input())
for x in range(a):
    b,c,d,e = map(int,input().split())
    f = (abs(d-b)+abs(e-c))
    if d!=b and c!=e:
        f += 1
    print(f)


for t in range(int(input())):
	res = 0
	[x1, y1, x2, y2] = list(map(int, input().split()))
	if( x1==x2 or y1==y2):
		res = abs(x2-x1+y2-y1)
	else:
		res = abs(x2-x1+y2-y1) + 2

	print(res)


for t in range(int(input())):
	res = 0
	[x1, y1, x2, y2] = list(map(int, input().split()))
	if( x1==x2 or y1==y2):
		res = abs(x2-x1)+abs(y2-y1)
	else:
		res = abs(x2-x1)+abs(y2-y1) + 2

	print(res)


for t in range(int(input())):
	n=int(input())
	dire = input()
	dire1 = dire.replace("-","")
	c=0
	for i in range(len(dire1)-1):
		if (dire1[i]!=dire1[i+1]):
			c+=1
	if(dire[0]!=dire[n-1] and dire[0]!="-" and dire[n-1]!="-" ):
		c+=1

	print(n-c)


for  i in range(int(input())):
    a,b,c,d = map(int,input().split())
    if a == c:
        print(abs(b-d))
    elif b == d:
        print(abs(a-c))
    elif a == c and b == d:
        print('0')
    else:
        z = (c-a) + (d-b)
        print(z+2)


for  i in range(int(input())):
    a,b,c,d = map(int,input().split())
    if a == c:
        print(abs(b-d))
    elif b == d:
        print(abs(a-c))
    elif a == c and b == d:
        print('0')
    else:
        z = abs(c-a) + abs(d-b)
        print(z+2)


for  i in range(int(input())):
    a,b,c,d = map(int,input().split())
    z = 0
    k = a+b
    l = c+d
    if abs(a-b) == 1:
        while k<l:
            z+=1
            k+=1
        print(z)
    else:
        while k<=l:
            z+=1
            k+=1
        print(z+1)


for  i in range(int(input())):
    a,b,c,d = map(int,input().split())
    z = 0
    k = a+b
    l = c+d
    if a == c:
        print(abs(b-d))
    elif b == d:
        print(abs(a-c))
    elif a == c and b == d:
        print('0')
    else:
        while k<l:
            z+=1
            k+=1
        print(z+2)


for _ in range(int(input())):
    x1, y1, x2, y2 = map(int, input().split())
    m = x2 - x1
    m += 3 * (y2 - y1)
    print(m)


for _ in range(int(input())):
    x1, y1, x2, y2 = map(int, input().split())
    p, q = abs(x2 - x1), abs(y2 - y1)
    m = 0
    if p == 0 and q != 0:
        m = q
    if p != 0 and q == 0:
        m = p
    if p != 0 and q != 0:
        m = p + q + 2
    print(m)


for _ in range(int(input())):
    x1, y1, x2, y2 = map(int, input().split())
    m = abs(x2 - x1)
    m += abs(3 * (y2 - y1))
    print(m)


for _ in range(int(input())):
   x1, y1, x2, y2 = map(int, input().split())
   dx = abs(x2-x1)
   dy = abs(y2-y1)
   if dx==0 and dy==0: t = 0
   elif dx==0: t = dy
   elif dy==0: t = dx
   else:
      t = dx+dy+2
   print(t)


for _ in range(int(input())):
   x1, y1, x2, y2 = map(int, input().split())
   dx = x2-x1
   dy = y2-y1
   if dx==0 and dy==0: t = 0
   elif dx==0: t = dy
   elif dy==0: t = dx
   else:
      t = dx+dy+2
   print(t)


t = int(input())
while t > 0:
    x1, y1, x2, y2 = map(int, input().split())
    time = 0
    time = abs(x2 - x1) + abs(y2 - y1)
    if x1 == x2 or y1 == y2:
        print(time)
    else:
        print(time + 2)


t = int(input())
while t > 0:
    x1, y1, x2, y2 = map(int, input().split())
    time = 0
    time = abs(x2 - x1) + abs(y2 - y1)
    if x1 == x2 or y1 == y2:
        print(time, "\n")
    else:
        print(time + 2, "\n")


t = int(input())
while t > 0:
    x1, y1, x2, y2 = map(int, input().split())
    time = 0
    time = abs(x2 - x1) + abs(y2 - y1)
    if x1 == x2 or y1 == y2:
        print(time, "\n")
    else:
        print(time + 2, "\n")
    t = t-1


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <map>
#include <vector>
using namespace std;
typedef pair<int, int> pii;
#define mp make_pair

const int N = (int)1e5 + 5;
const int M = 330;
vector<pii> col[N];
vector<int> big;
vector<int> par[N], sz[N];
map<int, int> reName[N];
map<pii, int> small;

int n, m;

int a[2 * N];
int s;

void readEdge()
{
	int v, u;
	int c;
	scanf("%d%d%d", &v, &u, &c);
	col[c].push_back(mp(v, u));
	return;
}

void read()
{
	scanf("%d%d", &n, &m);
	for (int i = 0; i < m; i++)
		readEdge();
	return;
}

void incSmall(int v, int u)
{
	pii tmp = mp(v, u);
	if (small.count(tmp) == 0)
		small[tmp] = 1;
	else
		small[tmp]++;
	return;
}

int getPar(int c, int v)
{
	return (par[c][v] == -1 ? v : par[c][v] = getPar(c, par[c][v]));
}

void unite(int c, int v, int u)
{
	v = getPar(c, v);
	u = getPar(c, u);
	if (v == u) return;
	if (sz[c][v] < sz[c][u]) swap(v, u);
	sz[c][v] += sz[c][u];
	par[c][u] = v;
	return;
}

void solveColor(int c)
{
	if ((int)col[c].size() == 0) return;
	int esz = (int)col[c].size();
	s = 0;
	for (int i = 0; i < esz; i++)
	{
		a[s++] = col[c][i].first;
		a[s++] = col[c][i].second;
	}
	sort(a, a + s);
	s = unique(a, a + s) - a;
//	for (int i = 0; i < s; i++)
//		printf("%d ", a[i]);
//	printf("\n");
	for (int i = 0; i < s; i++)
		reName[c][a[i]] = i;
	par[c].resize(s);
	sz[c].resize(s);
	for (int i = 0; i < s; i++)
	{
		par[c][i] = -1;
		sz[c][i] = 1;
	}
	for (int i = 0; i < esz; i++)
		unite(c, reName[c][col[c][i].first], reName[c][col[c][i].second]);
	if (s > M)
		big.push_back(c);
	else
	{
		for (int i = 0; i < s; i++)
			for (int j = i + 1; j < s; j++)
				if (getPar(c, i) == getPar(c, j))
					incSmall(a[i], a[j]);
	}
	return;
}

void solve()
{
	for (int i = 1; i <= m; i++)
		solveColor(i);
	return;
}

void query()
{
	int v, u;
	scanf("%d%d", &v, &u);
	if (v > u) swap(v, u);
	int ans = small[mp(v, u)];
	for (int i = 0; i < (int)big.size(); i++)
	{
		int c = big[i];
		if (reName[c].count(v) == 0 || reName[c].count(u) == 0) continue;
		ans += (int)(getPar(c, reName[c][v]) == getPar(c, reName[c][u]));
	}
	printf("%d\n", ans);
	return;
}

int main()
{
	read();
	solve();
	int q;
	scanf("%d", &q);
	for (int i = 0; i < q; i++)
		query();

	return 0;
}


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <map>
#include <vector>
using namespace std;
typedef pair<int, int> pii;
#define mp make_pair

const int N = (int)1e5 + 5;
const int M = 200;
vector<pii> col[N];
vector<int> big;
vector<int> par[N], sz[N];
map<int, int> reName[N];
map<pii, int> small;

int n, m;

int a[2 * N];
int s;

void readEdge()
{
	int v, u;
	int c;
	scanf("%d%d%d", &v, &u, &c);
	col[c].push_back(mp(v, u));
	return;
}

void read()
{
	scanf("%d%d", &n, &m);
	for (int i = 0; i < m; i++)
		readEdge();
	return;
}

void incSmall(int v, int u)
{
	pii tmp = mp(v, u);
	if (small.count(tmp) == 0)
		small[tmp] = 1;
	else
		small[tmp]++;
	return;
}

int getPar(int c, int v)
{
	return (par[c][v] == -1 ? v : par[c][v] = getPar(c, par[c][v]));
}

void unite(int c, int v, int u)
{
	v = getPar(c, v);
	u = getPar(c, u);
	if (v == u) return;
	if (sz[c][v] < sz[c][u]) swap(v, u);
	sz[c][v] += sz[c][u];
	par[c][u] = v;
	return;
}

void solveColor(int c)
{
	if ((int)col[c].size() == 0) return;
	int esz = (int)col[c].size();
	s = 0;
	for (int i = 0; i < esz; i++)
	{
		a[s++] = col[c][i].first;
		a[s++] = col[c][i].second;
	}
	sort(a, a + s);
	s = unique(a, a + s) - a;
//	for (int i = 0; i < s; i++)
//		printf("%d ", a[i]);
//	printf("\n");
	for (int i = 0; i < s; i++)
		reName[c][a[i]] = i;
	par[c].resize(s);
	sz[c].resize(s);
	for (int i = 0; i < s; i++)
	{
		par[c][i] = -1;
		sz[c][i] = 1;
	}
	for (int i = 0; i < esz; i++)
		unite(c, reName[c][col[c][i].first], reName[c][col[c][i].second]);
	if (s > M)
		big.push_back(c);
	else
	{
		for (int i = 0; i < s; i++)
			for (int j = i + 1; j < s; j++)
				if (getPar(c, i) == getPar(c, j))
					incSmall(a[i], a[j]);
	}
	return;
}

void solve()
{
	for (int i = 1; i <= m; i++)
		solveColor(i);
	return;
}

void query()
{
	int v, u;
	scanf("%d%d", &v, &u);
	if (v > u) swap(v, u);
	int ans = small[mp(v, u)];
	for (int i = 0; i < (int)big.size(); i++)
	{
		int c = big[i];
		if (reName[c].count(v) == 0 || reName[c].count(u) == 0) continue;
		ans += (int)(getPar(c, reName[c][v]) == getPar(c, reName[c][u]));
	}
	printf("%d\n", ans);
	return;
}

int main()
{
	read();
	solve();
	int q;
	scanf("%d", &q);
	for (int i = 0; i < q; i++)
		query();

	return 0;
}


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <map>
#include <vector>
using namespace std;
typedef pair<int, int> pii;
#define mp make_pair

const int N = (int)1e5 + 5;
const int M = 300;
vector<pii> col[N];
vector<int> big;
vector<int> par[N], sz[N];
map<int, int> reName[N];
map<pii, int> small;

int n, m;

int a[2 * N];
int s;

void readEdge()
{
	int v, u;
	int c;
	scanf("%d%d%d", &v, &u, &c);
	col[c].push_back(mp(v, u));
	return;
}

void read()
{
	scanf("%d%d", &n, &m);
	for (int i = 0; i < m; i++)
		readEdge();
	return;
}

void incSmall(int v, int u)
{
	pii tmp = mp(v, u);
	if (small.count(tmp) == 0)
		small[tmp] = 1;
	else
		small[tmp]++;
	return;
}

int getPar(int c, int v)
{
	return (par[c][v] == -1 ? v : par[c][v] = getPar(c, par[c][v]));
}

void unite(int c, int v, int u)
{
	v = getPar(c, v);
	u = getPar(c, u);
	if (v == u) return;
	if (sz[c][v] < sz[c][u]) swap(v, u);
	sz[c][v] += sz[c][u];
	par[c][u] = v;
	return;
}

void solveColor(int c)
{
	if ((int)col[c].size() == 0) return;
	int esz = (int)col[c].size();
	s = 0;
	for (int i = 0; i < esz; i++)
	{
		a[s++] = col[c][i].first;
		a[s++] = col[c][i].second;
	}
	sort(a, a + s);
	s = unique(a, a + s) - a;
//	for (int i = 0; i < s; i++)
//		printf("%d ", a[i]);
//	printf("\n");
	for (int i = 0; i < s; i++)
		reName[c][a[i]] = i;
	par[c].resize(s);
	sz[c].resize(s);
	for (int i = 0; i < s; i++)
	{
		par[c][i] = -1;
		sz[c][i] = 1;
	}
	for (int i = 0; i < esz; i++)
		unite(c, reName[c][col[c][i].first], reName[c][col[c][i].second]);
	if (s > M)
		big.push_back(c);
	else
	{
		for (int i = 0; i < s; i++)
			for (int j = i + 1; j < s; j++)
				if (getPar(c, i) == getPar(c, j))
					incSmall(a[i], a[j]);
	}
	return;
}

void solve()
{
	for (int i = 1; i <= m; i++)
		solveColor(i);
	return;
}

void query()
{
	int v, u;
	scanf("%d%d", &v, &u);
	if (v > u) swap(v, u);
	int ans = small[mp(v, u)];
	for (int i = 0; i < (int)big.size(); i++)
	{
		int c = big[i];
		if (reName[c].count(v) == 0 || reName[c].count(u) == 0) continue;
		ans += (int)(getPar(c, reName[c][v]) == getPar(c, reName[c][u]));
	}
	printf("%d\n", ans);
	return;
}

int main()
{
	read();
	solve();
	int q;
	scanf("%d", &q);
	for (int i = 0; i < q; i++)
		query();

	return 0;
}


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <map>
#include <vector>
using namespace std;
typedef pair<int, int> pii;
#define mp make_pair

const int N = (int)1e5 + 5;
const int M = 600;
vector<pii> col[N];
vector<int> big;
vector<int> par[N], sz[N];
map<int, int> reName[N];
map<pii, int> small;

int n, m;

int a[2 * N];
int s;

void readEdge()
{
	int v, u;
	int c;
	scanf("%d%d%d", &v, &u, &c);
	col[c].push_back(mp(v, u));
	return;
}

void read()
{
	scanf("%d%d", &n, &m);
	for (int i = 0; i < m; i++)
		readEdge();
	return;
}

void incSmall(int v, int u)
{
	pii tmp = mp(v, u);
	if (small.count(tmp) == 0)
		small[tmp] = 1;
	else
		small[tmp]++;
	return;
}

int getPar(int c, int v)
{
	return (par[c][v] == -1 ? v : par[c][v] = getPar(c, par[c][v]));
}

void unite(int c, int v, int u)
{
	v = getPar(c, v);
	u = getPar(c, u);
	if (v == u) return;
	if (sz[c][v] < sz[c][u]) swap(v, u);
	sz[c][v] += sz[c][u];
	par[c][u] = v;
	return;
}

void solveColor(int c)
{
	if ((int)col[c].size() == 0) return;
	int esz = (int)col[c].size();
	s = 0;
	for (int i = 0; i < esz; i++)
	{
		a[s++] = col[c][i].first;
		a[s++] = col[c][i].second;
	}
	sort(a, a + s);
	s = unique(a, a + s) - a;
//	for (int i = 0; i < s; i++)
//		printf("%d ", a[i]);
//	printf("\n");
	for (int i = 0; i < s; i++)
		reName[c][a[i]] = i;
	par[c].resize(s);
	sz[c].resize(s);
	for (int i = 0; i < s; i++)
	{
		par[c][i] = -1;
		sz[c][i] = 1;
	}
	for (int i = 0; i < esz; i++)
		unite(c, reName[c][col[c][i].first], reName[c][col[c][i].second]);
	if (s > M)
		big.push_back(c);
	else
	{
		for (int i = 0; i < s; i++)
			for (int j = i + 1; j < s; j++)
				if (getPar(c, i) == getPar(c, j))
					incSmall(a[i], a[j]);
	}
	return;
}

void solve()
{
	for (int i = 1; i <= m; i++)
		solveColor(i);
	return;
}

void query()
{
	int v, u;
	scanf("%d%d", &v, &u);
	if (v > u) swap(v, u);
	int ans = small[mp(v, u)];
	for (int i = 0; i < (int)big.size(); i++)
	{
		int c = big[i];
		if (reName[c].count(v) == 0 || reName[c].count(u) == 0) continue;
		ans += (int)(getPar(c, reName[c][v]) == getPar(c, reName[c][u]));
	}
	printf("%d\n", ans);
	return;
}

int main()
{
	read();
	solve();
	int q;
	scanf("%d", &q);
	for (int i = 0; i < q; i++)
		query();

	return 0;
}


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <map>
#include <vector>
using namespace std;
typedef pair<int, int> pii;
#define mp make_pair

const int N = (int)1e5 + 5;
const int M = 500;
vector<pii> col[N];
vector<int> big;
vector<int> par[N], sz[N];
map<int, int> reName[N];
map<pii, int> small;

int n, m;

int a[2 * N];
int s;

void readEdge()
{
	int v, u;
	int c;
	scanf("%d%d%d", &v, &u, &c);
	col[c].push_back(mp(v, u));
	return;
}

void read()
{
	scanf("%d%d", &n, &m);
	for (int i = 0; i < m; i++)
		readEdge();
	return;
}

void incSmall(int v, int u)
{
	pii tmp = mp(v, u);
	if (small.count(tmp) == 0)
		small[tmp] = 1;
	else
		small[tmp]++;
	return;
}

int getPar(int c, int v)
{
	return (par[c][v] == -1 ? v : par[c][v] = getPar(c, par[c][v]));
}

void unite(int c, int v, int u)
{
	v = getPar(c, v);
	u = getPar(c, u);
	if (v == u) return;
	if (sz[c][v] < sz[c][u]) swap(v, u);
	sz[c][v] += sz[c][u];
	par[c][u] = v;
	return;
}

void solveColor(int c)
{
	if ((int)col[c].size() == 0) return;
	int esz = (int)col[c].size();
	s = 0;
	for (int i = 0; i < esz; i++)
	{
		a[s++] = col[c][i].first;
		a[s++] = col[c][i].second;
	}
	sort(a, a + s);
	s = unique(a, a + s) - a;
//	for (int i = 0; i < s; i++)
//		printf("%d ", a[i]);
//	printf("\n");
	for (int i = 0; i < s; i++)
		reName[c][a[i]] = i;
	par[c].resize(s);
	sz[c].resize(s);
	for (int i = 0; i < s; i++)
	{
		par[c][i] = -1;
		sz[c][i] = 1;
	}
	for (int i = 0; i < esz; i++)
		unite(c, reName[c][col[c][i].first], reName[c][col[c][i].second]);
	if (s > M)
		big.push_back(c);
	else
	{
		for (int i = 0; i < s; i++)
			for (int j = i + 1; j < s; j++)
				if (getPar(c, i) == getPar(c, j))
					incSmall(a[i], a[j]);
	}
	return;
}

void solve()
{
	for (int i = 1; i <= m; i++)
		solveColor(i);
	return;
}

void query()
{
	int v, u;
	scanf("%d%d", &v, &u);
	if (v > u) swap(v, u);
	int ans = small[mp(v, u)];
	for (int i = 0; i < (int)big.size(); i++)
	{
		int c = big[i];
		if (reName[c].count(v) == 0 || reName[c].count(u) == 0) continue;
		ans += (int)(getPar(c, reName[c][v]) == getPar(c, reName[c][u]));
	}
	printf("%d\n", ans);
	return;
}

int main()
{
	read();
	solve();
	int q;
	scanf("%d", &q);
	for (int i = 0; i < q; i++)
		query();

	return 0;
}


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <map>
#include <vector>
using namespace std;
typedef pair<int, int> pii;
#define mp make_pair

const int N = (int)1e5 + 5;
const int M = 200;
vector<pii> col[N];
vector<int> big;
vector<int> par[N], sz[N];
map<int, int> reName[N];
map<pii, int> small;

int n, m;

int a[2 * N];
int s;

void readEdge()
{
	int v, u;
	int c;
	scanf("%d%d%d", &v, &u, &c);
	col[c].push_back(mp(v, u));
	return;
}

void read()
{
	scanf("%d%d", &n, &m);
	for (int i = 0; i < m; i++)
		readEdge();
	return;
}

void incSmall(int v, int u)
{
	pii tmp = mp(v, u);
	if (small.count(tmp) == 0)
		small[tmp] = 1;
	else
		small[tmp]++;
	return;
}

int getPar(int c, int v)
{
	return (par[c][v] == -1 ? v : par[c][v] = getPar(c, par[c][v]));
}

void unite(int c, int v, int u)
{
	v = getPar(c, v);
	u = getPar(c, u);
	if (v == u) return;
	if (sz[c][v] < sz[c][u]) swap(v, u);
	sz[c][v] += sz[c][u];
	par[c][u] = v;
	return;
}

void solveColor(int c)
{
	if ((int)col[c].size() == 0) return;
	int esz = (int)col[c].size();
	s = 0;
	for (int i = 0; i < esz; i++)
	{
		a[s++] = col[c][i].first;
		a[s++] = col[c][i].second;
	}
	sort(a, a + s);
	s = unique(a, a + s) - a;
//	for (int i = 0; i < s; i++)
//		printf("%d ", a[i]);
//	printf("\n");
	for (int i = 0; i < s; i++)
		reName[c][a[i]] = i;
	par[c].resize(s);
	sz[c].resize(s);
	for (int i = 0; i < s; i++)
	{
		par[c][i] = -1;
		sz[c][i] = 1;
	}
	for (int i = 0; i < esz; i++)
		unite(c, reName[c][col[c][i].first], reName[c][col[c][i].second]);
	if (s > M)
		big.push_back(c);
	else
	{
		for (int i = 0; i < s; i++)
			for (int j = i + 1; j < s; j++)
				if (getPar(c, i) == getPar(c, j))
					incSmall(a[i], a[j]);
	}
	return;
}

void solve()
{
	for (int i = 1; i <= m; i++)
		solveColor(i);
	return;
}

void query()
{
	int v, u;
	scanf("%d%d", &v, &u);
	if (v > u) swap(v, u);
	int ans = small[mp(v, u)];
	for (int i = 0; i < (int)big.size(); i++)
	{
		int c = big[i];
		ans += (int)(getPar(c, reName[c][v]) == getPar(c, reName[c][u]));
	}
	printf("%d\n", ans);
	return;
}

int main()
{
	read();
	solve();
	int q;
	scanf("%d", &q);
	for (int i = 0; i < q; i++)
		query();

	return 0;
}


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <map>
#include <vector>
using namespace std;
typedef pair<int, int> pii;
#define mp make_pair

const int N = (int)1e5 + 5;
const int M = 400;
vector<pii> col[N];
vector<int> big;
vector<int> par[N], sz[N];
map<int, int> reName[N];
map<pii, int> small;

int n, m;

int a[2 * N];
int s;

void readEdge()
{
	int v, u;
	int c;
	scanf("%d%d%d", &v, &u, &c);
	col[c].push_back(mp(v, u));
	return;
}

void read()
{
	scanf("%d%d", &n, &m);
	for (int i = 0; i < m; i++)
		readEdge();
	return;
}

void incSmall(int v, int u)
{
	pii tmp = mp(v, u);
	if (small.count(tmp) == 0)
		small[tmp] = 1;
	else
		small[tmp]++;
	return;
}

int getPar(int c, int v)
{
	return (par[c][v] == -1 ? v : par[c][v] = getPar(c, par[c][v]));
}

void unite(int c, int v, int u)
{
	v = getPar(c, v);
	u = getPar(c, u);
	if (v == u) return;
	if (sz[c][v] < sz[c][u]) swap(v, u);
	sz[c][v] += sz[c][u];
	par[c][u] = v;
	return;
}

void solveColor(int c)
{
	if ((int)col[c].size() == 0) return;
	int esz = (int)col[c].size();
	s = 0;
	for (int i = 0; i < esz; i++)
	{
		a[s++] = col[c][i].first;
		a[s++] = col[c][i].second;
	}
	sort(a, a + s);
	s = unique(a, a + s) - a;
//	for (int i = 0; i < s; i++)
//		printf("%d ", a[i]);
//	printf("\n");
	for (int i = 0; i < s; i++)
		reName[c][a[i]] = i;
	par[c].resize(s);
	sz[c].resize(s);
	for (int i = 0; i < s; i++)
	{
		par[c][i] = -1;
		sz[c][i] = 1;
	}
	for (int i = 0; i < esz; i++)
		unite(c, reName[c][col[c][i].first], reName[c][col[c][i].second]);
	if (s > M)
		big.push_back(c);
	else
	{
		for (int i = 0; i < s; i++)
			for (int j = i + 1; j < s; j++)
				if (getPar(c, i) == getPar(c, j))
					incSmall(a[i], a[j]);
	}
	return;
}

void solve()
{
	for (int i = 1; i <= m; i++)
		solveColor(i);
	return;
}

void query()
{
	int v, u;
	scanf("%d%d", &v, &u);
	if (v > u) swap(v, u);
	int ans = small[mp(v, u)];
	for (int i = 0; i < (int)big.size(); i++)
	{
		int c = big[i];
		if (reName[c].count(v) == 0 || reName[c].count(u) == 0) continue;
		ans += (int)(getPar(c, reName[c][v]) == getPar(c, reName[c][u]));
	}
	printf("%d\n", ans);
	return;
}

int main()
{
	read();
	solve();
	int q;
	scanf("%d", &q);
	for (int i = 0; i < q; i++)
		query();

	return 0;
}


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <map>
#include <vector>
using namespace std;
typedef pair<int, int> pii;
#define mp make_pair

const int N = (int)1e5 + 5;
const int M = 250;
vector<pii> col[N];
vector<int> big;
vector<int> par[N], sz[N];
map<int, int> reName[N];
map<pii, int> small;

int n, m;

int a[2 * N];
int s;

void readEdge()
{
	int v, u;
	int c;
	scanf("%d%d%d", &v, &u, &c);
	col[c].push_back(mp(v, u));
	return;
}

void read()
{
	scanf("%d%d", &n, &m);
	for (int i = 0; i < m; i++)
		readEdge();
	return;
}

void incSmall(int v, int u)
{
	pii tmp = mp(v, u);
	if (small.count(tmp) == 0)
		small[tmp] = 1;
	else
		small[tmp]++;
	return;
}

int getPar(int c, int v)
{
	return (par[c][v] == -1 ? v : par[c][v] = getPar(c, par[c][v]));
}

void unite(int c, int v, int u)
{
	v = getPar(c, v);
	u = getPar(c, u);
	if (v == u) return;
	if (sz[c][v] < sz[c][u]) swap(v, u);
	sz[c][v] += sz[c][u];
	par[c][u] = v;
	return;
}

void solveColor(int c)
{
	if ((int)col[c].size() == 0) return;
	int esz = (int)col[c].size();
	s = 0;
	for (int i = 0; i < esz; i++)
	{
		a[s++] = col[c][i].first;
		a[s++] = col[c][i].second;
	}
	sort(a, a + s);
	s = unique(a, a + s) - a;
//	for (int i = 0; i < s; i++)
//		printf("%d ", a[i]);
//	printf("\n");
	for (int i = 0; i < s; i++)
		reName[c][a[i]] = i;
	par[c].resize(s);
	sz[c].resize(s);
	for (int i = 0; i < s; i++)
	{
		par[c][i] = -1;
		sz[c][i] = 1;
	}
	for (int i = 0; i < esz; i++)
		unite(c, reName[c][col[c][i].first], reName[c][col[c][i].second]);
	if (s > M)
		big.push_back(c);
	else
	{
		for (int i = 0; i < s; i++)
			for (int j = i + 1; j < s; j++)
				if (getPar(c, i) == getPar(c, j))
					incSmall(a[i], a[j]);
	}
	return;
}

void solve()
{
	for (int i = 1; i <= m; i++)
		solveColor(i);
	return;
}

void query()
{
	int v, u;
	scanf("%d%d", &v, &u);
	if (v > u) swap(v, u);
	int ans = small[mp(v, u)];
	for (int i = 0; i < (int)big.size(); i++)
	{
		int c = big[i];
		if (reName[c].count(v) == 0 || reName[c].count(u) == 0) continue;
		ans += (int)(getPar(c, reName[c][v]) == getPar(c, reName[c][u]));
	}
	printf("%d\n", ans);
	return;
}

int main()
{
	read();
	solve();
	int q;
	scanf("%d", &q);
	for (int i = 0; i < q; i++)
		query();

	return 0;
}


#include<iostream>
#include<fstream>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#include<set>
#include<string>
#include<cstdio>
#include<map>
#include<unordered_map>

#define forn(i, n)  for(int i = 0; i < n; i++)
#define ll long long
#define mp make_pair
#define pb push_back
#define pii pair<int,int>
#define rank rang
using namespace std;

const int md = 1000000007;
const int maxn = 101010;
const int lol = 30001;
const int maxn4 = 4 * maxn;
const ll inf = 2020202020202020202LL;

vector < set < int > > g(maxn);
int n,m, q;

vector < unordered_map < int, int > > parent(maxn);
map < pii, int > alr;

int find_set (int v, int c) {
    if (parent[c].find(v) == parent[c].end() || v == parent[c][v])
        return v;
    return parent[c][v] = find_set (parent[c][v], c);
}

void union_sets (int a, int b, int c) {
    a = find_set (a, c);
    b = find_set (b, c);
    if (a != b) {
         if (rand() % 2)
            swap(a , b);
        parent[c][b] = a;
    }
}
vector < vector < pair < int, int > > > as(maxn);

int main()
{
    scanf("%d %d", &n, &m);
    forn(i, m)
    {
        int a, b, c;

        scanf("%d %d %d", &a, &b, &c);
                a--;
        b--;
        g[a].insert(c);
        g[b].insert(c);
        union_sets(a, b, c);
    }
    forn(i, n)
        for (set < int > :: iterator it = g[i].begin(); it!= g[i].end(); it++)
            as[i].push_back(mp(*it, find_set(i, *it)));

    scanf("%d", &q);
    forn(i, q)
    {
        int a, b, ans = 0;
        scanf("%d %d", &a, &b);
        a--;b--;
        if (g[a].size() > g[b].size() || g[a].size() == g[b].size() && a > b)
            swap(a, b);
        if (alr.find(mp(a, b)) == alr.end())
        {
            forn(i, as[a].size())
                if (binary_search(as[b].begin(), as[b].end(), as[a][i]))
                    ans++;
            alr.insert(mp(mp(a,b), ans));       }
        else
            ans = alr.find(mp(a, b))->second;
        printf("%d\n", ans);
    }
    return 0;
}


#include<iostream>
#include<fstream>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#include<set>
#include<string>
#include<cstdio>
#include<map>
#include<unordered_map>

#define forn(i, n)  for(int i = 0; i < n; i++)
#define ll long long
#define mp make_pair
#define pb push_back
#define pii pair<int,int>
#define rank rang
using namespace std;

const int md = 1000000007;
const int maxn = 101010;
const int lol = 30001;
const int maxn4 = 4 * maxn;
const ll inf = 2020202020202020202LL;

vector < set < int > > g(maxn);
int n,m, q;

vector < unordered_map < int, int > > parent(maxn), rank(maxn);
map < pii, int > alr;

void make_set (int v, int c) {
    if (parent[c].find(v) != parent[c].end())
        return;
    parent[c][v] = v;
    rank[c][v] = 0;
}

int find_set (int v, int c) {
    if (parent[c].find(v) == parent[c].end())
        return -1;
    if (v == parent[c][v])
        return v;
    return parent[c][v] = find_set (parent[c][v], c);
}

void union_sets (int a, int b, int c) {
    a = find_set (a, c);
    b = find_set (b, c);
    if (a != b) {
        if (rank[c][a] < rank[c][b])
            swap (a, b);
        parent[c][b] = a;
        if (rank[c][a] == rank[c][b])
            ++rank[c][a];
    }
}
int main()
{
    scanf("%d %d", &n, &m);
    forn(i, m)
    {
        int a, b, c;
        scanf("%d %d %d", &a, &b, &c);
        g[a].insert(c);
        g[b].insert(c);
        make_set(a, c);
        make_set(b, c);
        union_sets(a, b, c);
    }
    scanf("%d", &q);
    forn(i, q)
    {
        int a, b, ans = 0;
        scanf("%d %d", &a, &b);
        if (g[a].size() > g[b].size())
            swap(a, b);
        if (g[a].size() == g[b].size() && a > b)
            swap(a, b);
        if (alr.find(mp(a, b)) == alr.end())
        {

            for(set < int > :: iterator it = g[a].begin(); it!= g[a].end(); ++it)
            {
                int c = *it;
                int u = 1;
                if (find_set(b, c) != find_set(a, c))
                    u = 0;
                ans+=u;
            }
            alr.insert(mp(mp(a,b), ans));

        }
        else
            ans = alr.find(mp(a, b))->second;
        printf("%d\n", ans);
    }
    return 0;
}


#include<iostream>
#include<fstream>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#include<set>
#include<string>
#include<cstdio>
#include<map>
#include<unordered_map>

#define forn(i, n)  for(int i = 0; i < n; i++)
#define ll long long
#define mp make_pair
#define pb push_back
#define pii pair<int,int>
#define rank rang
using namespace std;

const int md = 1000000007;
const int maxn = 101010;
const int lol = 30001;
const int maxn4 = 4 * maxn;
const ll inf = 2020202020202020202LL;

vector < set < int > > g(maxn);
int n,m, q;

vector < map < int, int > > parent(maxn), rank(maxn);
map < pii, int > alr;

void make_set (int v, int c) {
    if (parent[c].find(v) != parent[c].end())
        return;
    parent[c][v] = v;
    rank[c][v] = 0;
}

int find_set (int v, int c) {
    if (parent[c].find(v) == parent[c].end())
        return -1;
    if (v == parent[c][v])
        return v;
    return parent[c][v] = find_set (parent[c][v], c);
}

void union_sets (int a, int b, int c) {
    a = find_set (a, c);
    b = find_set (b, c);
    if (a != b) {
        if (rank[c][a] < rank[c][b])
            swap (a, b);
        parent[c][b] = a;
        if (rank[c][a] == rank[c][b])
            ++rank[c][a];
    }
}
int main()
{
    scanf("%d %d", &n, &m);
    forn(i, m)
    {
        int a, b, c;
        scanf("%d %d %d", &a, &b, &c);
        g[a].insert(c);
        g[b].insert(c);
        make_set(a, c);
        make_set(b, c);
        union_sets(a, b, c);
    }
    scanf("%d", &q);
    forn(i, q)
    {
        int a, b, ans = 0;
        scanf("%d %d", &a, &b);
        if (g[a].size() > g[b].size())
            swap(a, b);
        if (g[a].size() == g[b].size() && a > b)
            swap(a, b);
        if (alr.find(mp(a, b)) == alr.end())
        {

            for(set < int > :: iterator it = g[a].begin(); it!= g[a].end(); ++it)
            {
                int c = *it;
                if (find_set(b, c) == find_set(a, c))
                    ans++;
            }
            alr.insert(mp(mp(a,b), ans));       }
        else
            ans = alr.find(mp(a, b))->second;
        printf("%d\n", ans);
    }
    return 0;
}


#include<iostream>
#include<fstream>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#include<set>
#include<string>
#include<cstdio>
#include<map>
#include<unordered_map>

#define forn(i, n)  for(int i = 0; i < n; i++)
#define ll long long
#define mp make_pair
#define pb push_back
#define pii pair<int,int>
#define rank rang
using namespace std;

const int md = 1000000007;
const int maxn = 101010;
const int lol = 30001;
const int maxn4 = 4 * maxn;
const ll inf = 2020202020202020202LL;

vector < set < int > > g(maxn);
int n,m, q;

vector < map < int, int > > parent(maxn);
map < pii, int > alr;

int find_set (int v, int c) {
    if (parent[c].find(v) == parent[c].end() || v == parent[c][v])
        return v;
    return parent[c][v] = find_set (parent[c][v], c);
}

void union_sets (int a, int b, int c) {
    a = find_set (a, c);
    b = find_set (b, c);
    if (a != b) {
         if (rand() % 2)
            swap(a , b);
        parent[c][b] = a;
    }
}
int main()
{
    scanf("%d %d", &n, &m);
    forn(i, m)
    {
        int a, b, c;
        scanf("%d %d %d", &a, &b, &c);
        g[a].insert(c);
        g[b].insert(c);
        union_sets(a, b, c);
    }
    scanf("%d", &q);
    forn(i, q)
    {
        int a, b, ans = 0;
        scanf("%d %d", &a, &b);
        if (g[a].size() > g[b].size() || g[a].size() == g[b].size() && a > b)
            swap(a, b);
        if (alr.find(mp(a, b)) == alr.end())
        {
            for(set < int > :: iterator it = g[a].begin(); it!= g[a].end(); ++it)
            {
                int c = *it;
                if (find_set(b, c) == find_set(a, c))
                    ans++;
            }
            alr.insert(mp(mp(a,b), ans));       }
        else
            ans = alr.find(mp(a, b))->second;
        printf("%d\n", ans);
    }
    return 0;
}


#include<iostream>
#include<fstream>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#include<set>
#include<string>
#include<cstdio>
#include<map>
#include<unordered_map>

#define forn(i, n)  for(int i = 0; i < n; i++)
#define ll long long
#define mp make_pair
#define pb push_back
#define pii pair<int,int>
#define rank rang
using namespace std;

const int md = 1000000007;
const int maxn = 101010;
const int lol = 30001;
const int maxn4 = 4 * maxn;
const ll inf = 2020202020202020202LL;

vector < set < int > > g(maxn);
int n,m, q;

vector < unordered_map < int, int > > parent(maxn), rank(maxn);
map < pii, int > alr;

void make_set (int v, int c) {
    if (parent[c].find(v) != parent[c].end())
        return;
    parent[c][v] = v;
    rank[c][v] = 0;
}

int find_set (int v, int c) {
    if (parent[c].find(v) == parent[c].end())
        return -1;
    if (v == parent[c][v])
        return v;
    return parent[c][v] = find_set (parent[c][v], c);
}

void union_sets (int a, int b, int c) {
    a = find_set (a, c);
    b = find_set (b, c);
    if (a != b) {
        if (rank[c][a] < rank[c][b])
            swap (a, b);
        parent[c][b] = a;
        if (rank[c][a] == rank[c][b])
            ++rank[c][a];
    }
}
int main()
{
    ios::ios_base::sync_with_stdio(false);
    cin>>n>>m;
    forn(i, m)
    {
        int a, b, c;
        scanf("%d %d %d", &a, &b, &c);
        //cin>>a>>b>>c;
        g[a].insert(c);
        g[b].insert(c);
        make_set(a, c);
        make_set(b, c);
        union_sets(a, b, c);
    }
    cin>>q;
    forn(i, q)
    {
        int a, b, ans = 0;
        scanf("%d %d", &a, &b);
        cin>>a>>b;
        if (g[a].size() > g[b].size())
            swap(a, b);
        if (g[a].size() == g[b].size() && a > b)
            swap(a, b);
        if (alr.find(mp(a, b)) == alr.end())
        {

            for(set < int > :: iterator it = g[a].begin(); it!= g[a].end(); ++it)
            {
                int c = *it;
                int u = 1;
                if (find_set(b, c) != find_set(a, c))
                    u = 0;
                ans+=u;
            }
            alr.insert(mp(mp(a,b), ans));

        }
        else
            ans = alr.find(mp(a, b))->second;
        printf("%d\n", ans);
    }
    return 0;
}


#include<iostream>
#include<fstream>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#include<set>
#include<string>
#include<cstdio>
#include<map>
#include<unordered_map>

#define forn(i, n)  for(int i = 0; i < n; i++)
#define ll long long
#define mp make_pair
#define pb push_back
#define pii pair<int,int>
#define rank rang
using namespace std;

const int md = 1000000007;
const int maxn = 101010;
const int lol = 30001;
const int maxn4 = 4 * maxn;
const ll inf = 2020202020202020202LL;

vector < set < int > > g(maxn);
int n,m, q;

vector < unordered_map < int, int > > parent(maxn), rank(maxn);
map < pii, int > alr;

void make_set (int v, int c) {
    if (parent[c].find(v) != parent[c].end())
        return;
    parent[c][v] = v;
    rank[c][v] = 0;
}

int find_set (int v, int c) {
    if (parent[c].find(v) == parent[c].end())
        return -1;
    if (v == parent[c][v])
        return v;
    return parent[c][v] = find_set (parent[c][v], c);
}

void union_sets (int a, int b, int c) {
    a = find_set (a, c);
    b = find_set (b, c);
    if (a != b) {
        if (rank[c][a] < rank[c][b])
            swap (a, b);
        parent[c][b] = a;
        if (rank[c][a] == rank[c][b])
            ++rank[c][a];
    }
}
int main()
{
    ios::ios_base::sync_with_stdio(false);
    cin>>n>>m;
    forn(i, m)
    {
        int a, b, c;
        cin>>a>>b>>c;
        g[a].insert(c);
        g[b].insert(c);
        make_set(a, c);
        make_set(b, c);
        union_sets(a, b, c);
    }
    cin>>q;
    forn(i, q)
    {
        int a, b, ans = 0;
        cin>>a>>b;
        if (g[a].size() > g[b].size())
            swap(a, b);
        if (alr.find(mp(a, b)) == alr.end())
        {

            for(set < int > :: iterator it = g[a].begin(); it!= g[a].end(); ++it)
            {
                int c = *it;
                int u = 1;
                if (find_set(b, c) != find_set(a, c))
                    u = 0;
                ans+=u;
            }
            alr.insert(mp(mp(a,b), ans));
            cout<<ans;
        }
        else
            cout<<alr.find(mp(a, b))->second;
        cout<<endl;
    }
    return 0;
}


#include <iostream>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;

int res;
const int size = 100010;
bool vis[size];
int degree[size];
vector<int>edge[size] , ve[size] , graph;
queue<int> q;

void init( )
{
	for( int i = 0 ; i<size ; i++ )
	{
		ve[i].clear();
		edge[i].clear();
	}
	memset( vis , false , sizeof(vis) );
	memset( degree , 0 , sizeof(degree) );
	res = 0;
}

void wcc( int u )
{
	vis[u] = true;
	int veSize = edge[u].size();
	++ res;
	graph.push_back(u);
	for( int i = 0 ; i<veSize ; i++ )
	{
		int v = edge[u][i];
		if( vis[v] )
			continue;
		wcc( v );
	}
}

bool loop( )
{
	int veSize = graph.size();
	int num = 0;
	for( int i = 0 ; i<veSize ; i++ )
	{
		if( degree[ graph[i] ] == 0 )
		{
			++ num;
			q.push( graph[i] );
			break;
		}
	}
	if( q.empty() )
	{
		return false;//有环
	}
	while( !q.empty() )
	{
		int u = q.front();
		q.pop();
		int cnt = ve[u].size();
		for( int i = 0 ; i<cnt ; i++ )
		{
			int v = ve[u][i];
			-- degree[v];
			if( !degree[v] )
			{
				q.push( v );
				++ num;
			}
		}
	}
	return num == veSize;//相等就是没有环 不相等就是有环
}

int main()
{
	init( );
	bool flag;
	int a , b , n , m;
	cin >> n >> m;
	for( int i = 0 ; i<m ; i++ )
	{
		cin >> a >> b;
		ve[a].push_back(b);
		edge[a].push_back(b);
		edge[b].push_back(a);
		++ degree[b];
	}
	for( int i = 1 ; i<=n ; i++ )
	{
		if( !q.empty() )
		{
			q.pop();
		}
		if( graph.size()!=0 )
			graph.clear();
		if( vis[i] )
			continue;
		wcc( i );
		flag = loop( );
		res -= flag ? 1 : 0;
	}
	cout << res << endl;
	return 0;
}


#include <iostream>
#include <cstring>
#include <map>
#include <vector>
#include <algorithm>
using namespace std;

typedef pair<int,int> pi;
const int size = 100010;
const int bound = 100;

int n , m , qq;
int res[size] , arr[size] , father[size];
vector<pi> edge[size];
pi q[size];
map<int,int> ans[size];

int find( int x )
{
	return father[x] == -1 ? x : father[x] = find( father[x] );
}

void merge( int x , int y )
{
	int xx = find( x ) , yy = find( y );
	if( xx!=yy )
	{
		father[xx] = yy;
	}
}

void solve( )
{
	for( int c = 1 ; c<=m ; c++ )
	{
		for( auto i : edge[c] )
		{
			merge( i.first , i.second );
		}
		if( edge[c].size() > bound )
		{
			for( int j = 0 ; j < qq ; j++ )
			{
				if( find( q[j].first ) == find( q[j].second) )
				{
					++ res[j];
				}
			}
		}
		else
		{
			int num = 0;
			for( auto i : edge[c] )
			{
				arr[num++] = i.first;
				arr[num++] = i.second;
			}
			sort( arr , arr+num );
			num = unique( arr , arr+num ) - arr;
			for( int u = 0 ; u<num ; u++ )
			{
				for( int v = u + 1 ; v<num ; v++ )
				{
					if( find( arr[u] ) == find( arr[v] ) )
					{
						++ ans[ arr[u] ][ arr[v] ];
					}
				}
			}
		}
		for( auto i : edge[c] )
		{
			father[ i.first ] = father[ i.second ] = -1;
		}
	}
}
int main()
{
	int a , b , c;
	memset( father , -1 , sizeof(father) );
	memset( res , 0 , sizeof(res) );
	cin >> n >> m;
	for( int i = 0 ; i<m ; i++ )
	{
		cin >> a >> b >> c;
		edge[c].push_back( make_pair(a,b) );
	}
	cin >> qq;
	for( int i = 0 ; i<qq ; i++ )
	{
		cin >> q[i].first >> q[i].second;
		if( q[i].first > q[i].second )
			swap( q[i].first , q[i].second );
	}
	solve( );
	for( int i = 0 ; i<qq ; i++ )
	{
		cout << res[i] + ans[ q[i].first ][ q[i].second ] << endl;
	}
	return 0;
}


#include <iostream>
#include <cstring>
#include <map>
#include <vector>
#include <algorithm>
using namespace std;

typedef pair<int,int> pi;
const int size = 100010;
const int bound = 100;

int n , m , qq;
int res[size] , arr[size] , father[size];
vector<pi> edge[size];
pi q[size];
map<int,int> ans[size];

int find( int x )
{
	return father[x] == -1 ? x : father[x] = find( father[x] );
}

void merge( int x , int y )
{
	int xx = find( x ) , yy = find( y );
	if( xx!=yy )
	{
		father[xx] = yy;
	}
}

void solve( )
{
	for( int c = 1 ; c<=m ; c++ )
	{
		for( auto i : edge[c] )
		{
			merge( i.first , i.second );
		}
		//if( edge[c].size() > bound )
		//{
			for( int j = 0 ; j < qq ; j++ )
			{
				if( find( q[j].first ) == find( q[j].second) )
				{
					++ res[j];
				}
			}
	//	}
		/*
		else
		{
			int num = 0;
			for( auto i : edge[c] )
			{
				arr[num++] = i.first;
				arr[num++] = i.second;
			}
			sort( arr , arr+num );
			num = unique( arr , arr+num ) - arr;
			for( int u = 0 ; u<num ; u++ )
			{
				for( int v = u + 1 ; v<num ; v++ )
				{
					if( find( arr[u] ) == find( arr[v] ) )
					{
						++ ans[ arr[u] ][ arr[v] ];
					}
				}
			}
		}
		*/
		for( auto i : edge[c] )
		{
			father[ i.first ] = father[ i.second ] = -1;
		}
	}
}

int main()
{
	int a , b , c;
	memset( father , -1 , sizeof(father) );
	memset( res , 0 , sizeof(res) );
	cin >> n >> m;
	for( int i = 0 ; i<m ; i++ )
	{
		cin >> a >> b >> c;
		edge[c].push_back( make_pair(a,b) );
	}
	cin >> qq;
	for( int i = 0 ; i<qq ; i++ )
	{
		cin >> q[i].first >> q[i].second;
		if( q[i].first > q[i].second )
			swap( q[i].first , q[i].second );
	}
	solve( );
	for( int i = 0 ; i<qq ; i++ )
	{
		cout << res[i] + ans[ q[i].first ][ q[i].second ] << endl;
	}
	return 0;
}


#include <iostream>
#include <cstring>
#include <map>
#include <vector>
#include <algorithm>
using namespace std;

typedef pair<int,int> pi;
const int size = 100010;
const int bound = 100;

int n , m , qq;
int res[size] , arr[size] , father[size];
vector<pi> edge[size];
pi q[size];
map<int,int> ans[size];

int find( int x )
{
	return father[x] == -1 ? x : father[x] = find( father[x] );
}

void merge( int x , int y )
{
	int xx = find( x ) , yy = find( y );
	if( xx!=yy )
	{
		father[xx] = yy;
	}
}

void solve( )
{
	for( int c = 1 ; c<=m ; c++ )
	{
		for( auto i : edge[c] )
		{
			merge( i.first , i.second );
		}
		if( edge[c].size() > bound )
		{
			for( int j = 0 ; j < qq ; j++ )
			{
				if( find( q[j].first ) == find( q[j].second) )
				{
					++ res[j];
				}
			}
		}
		else
		{
			int num = 0;
			for( auto i : edge[c] )
			{
				arr[num++] = i.first;
				arr[num++] = i.second;
			}
			sort( arr , arr+num );
			num = unique( arr , arr+num ) - arr;
			for( int u = 0 ; u<num ; u++ )
			{
				for( int v = u + 1 ; v<num ; v++ )
				{
					if( find( arr[u] ) == find( arr[v] ) )
					{
						++ ans[ arr[u] ][ arr[v] ];
					}
				}
			}
		}
		for( auto i : edge[c] )
		{
			father[ i.first ] = father[ i.second ] = -1;
		}
	}
}

int main()
{
	int a , b , c;
	memset( father , -1 , sizeof(father) );
	memset( res , 0 , sizeof(res) );
	cin >> n >> m;
	for( int i = 0 ; i<m ; i++ )
	{
		cin >> a >> b >> c;
		edge[c].push_back( make_pair(a,b) );
	}
	cin >> qq;
	for( int i = 0 ; i<qq ; i++ )
	{
		cin >> q[i].first >> q[i].second;
		//if( q[i].first > q[i].second )
		//	swap( q[i].first , q[i].second );
	}
	solve( );
	for( int i = 0 ; i<qq ; i++ )
	{
		cout << res[i] + max( ans[ q[i].first ][ q[i].second ] , ans[ q[i].second ][ q[i].first ] ) << endl;
	}
	return 0;
}


import java.io.*;
import java.util.*;

public class CF {
	FastScanner in;
	PrintWriter out;

	class Edge implements Comparable<Edge> {
		int fr, to, color;

		public Edge(int fr, int to, int color) {
			super();
			this.fr = fr;
			this.to = to;
			this.color = color;
		}

		@Override
		public int compareTo(Edge o) {
			return Integer.compare(color, o.color);
		}

	}

	int[] parent;

	int get(int x) {
		return parent[x] == x ? x : (parent[x] = get(parent[x]));
	}

	void unite(int x, int y) {
		x = get(x);
		y = get(y);
		if (x != y) {
			parent[x] = y;
		}
	}

	int qSz;
	int[] q;
	int[] bigId;
	int[] answer;
	ArrayList<Integer>[] all;
	ArrayList<Integer>[] qu;
	int[]fr;
	int[] to;
	int[] bigs;
	int[][] cnt;

	void upd() {
		for (int i = 0; i < qSz; i++) {
			int v = q[i];
			int root = get(v);
			if (bigId[v] == -1) {
				for (int curQ : qu[v]) {
					int another = fr[curQ] + to[curQ] - v;
					if (get(another) == root) {
						answer[curQ]++;
					}
				}
			}
			all[root].add(v);
		}
		for (int i = 0; i < bigs.length; i++) {
			int v = bigs[i];
			int root = get(v);
			for (int x : all[root])
				if (x != v && bigId[x] != -1) {
					cnt[i][bigId[x]]++;
				}
		}
		for (int i = 0; i < qSz; i++) {
			int v = q[i];
			int root = get(v);
			all[root].clear();
		}
		for (int i = 0; i < qSz; i++) {
			parent[q[i]] = q[i];
		}
	}

	void solve() {
		int n = in.nextInt();
		int m = in.nextInt();
		Edge[] allE = new Edge[m];
		for (int i = 0; i < m; i++) {
			allE[i] = new Edge(in.nextInt() - 1, in.nextInt() - 1, in.nextInt());
		}
		final int BIG = 444;
		int[] colors = new int[n];
		for (Edge e : allE) {
			colors[e.fr]++;
			colors[e.to]++;
		}
		bigId = new int[n];
		int cntBig = 0;
		Arrays.fill(bigId, -1);
		for (int i = 0; i < n; i++) {
			if (colors[i] >= BIG) {
				bigId[i] = cntBig++;
			}
		}
		bigs = new int[cntBig];
		for (int i = 0; i < n; i++) {
			if (bigId[i] != -1) {
				bigs[bigId[i]] = i;
			}
		}
		int qq = in.nextInt();
		fr = new int[qq];
		to = new int[qq];
		for (int i = 0; i < qq; i++) {
			fr[i] = in.nextInt() - 1;
			to[i] = in.nextInt() - 1;
		}
		answer = new int[qq];
		qu = new ArrayList[n];
		for (int i = 0; i < n; i++) {
			qu[i] = new ArrayList<>();
		}
		for (int i = 0; i < qq; i++) {
			if (bigId[fr[i]] == -1 || bigId[to[i]] == -1) {
				if (colors[fr[i]] < colors[to[i]]) {
					qu[fr[i]].add(i);
				} else {
					qu[to[i]].add(i);
				}
			}
		}
		Arrays.sort(allE);
		int lastColor = -1;
		q = new int[n];
		int[] used = new int[n];
		parent = new int[n];
		cnt = new int[cntBig][cntBig];
		for (int i = 0; i < n; i++) {
			parent[i] = i;
		}
		int time = 0;
		qSz = 0;
		all = new ArrayList[n + 1];
		for (int i = 0; i < all.length; i++) {
			all[i] = new ArrayList<>();
		}
		for (Edge e : allE) {
			if (e.color != lastColor) {
				upd();
				time++;
				qSz = 0;
			}
			if (used[e.fr] != time) {
				used[e.fr] = time;
				q[qSz++] = e.fr;
			}
			if (used[e.to] != time) {
				used[e.to] = time;
				q[qSz++] = e.to;
			}
			unite(e.fr, e.to);
			lastColor = e.color;
		}
		upd();
		for (int i = 0; i < qq; i++) {
			if (bigId[fr[i]] != -1 && bigId[to[i]] != -1) {
				answer[i] = cnt[bigId[fr[i]]][bigId[to[i]]];
			}
		}
		for (int ans : answer) {
			out.println(ans);
		}
	}

	void runIO() {

		in = new FastScanner(System.in);
		out = new PrintWriter(System.out);

		solve();

		out.close();
	}

	void run() {
		try {
			in = new FastScanner(new File("test.in"));
			out = new PrintWriter(new File("test.out"));

			solve();

			out.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
	}

	class FastScanner {
		BufferedReader br;
		StringTokenizer st;

		public FastScanner(File f) {
			try {
				br = new BufferedReader(new FileReader(f));
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
		}

		public FastScanner(InputStream f) {
			br = new BufferedReader(new InputStreamReader(f));
		}

		String next() {
			while (st == null || !st.hasMoreTokens()) {
				String s = null;
				try {
					s = br.readLine();
				} catch (IOException e) {
					e.printStackTrace();
				}
				if (s == null)
					return null;
				st = new StringTokenizer(s);
			}
			return st.nextToken();
		}

		boolean hasMoreTokens() {
			while (st == null || !st.hasMoreTokens()) {
				String s = null;
				try {
					s = br.readLine();
				} catch (IOException e) {
					e.printStackTrace();
				}
				if (s == null)
					return false;
				st = new StringTokenizer(s);
			}
			return true;
		}

		int nextInt() {
			return Integer.parseInt(next());
		}

		long nextLong() {
			return Long.parseLong(next());
		}

		double nextDouble() {
			return Double.parseDouble(next());
		}
	}

	public static void main(String[] args) {
		new CF().runIO();
	}
}


import java.io.*;
import java.util.*;

public class CF {
	FastScanner in;
	PrintWriter out;

	class Edge implements Comparable<Edge> {
		int fr, to, color;

		public Edge(int fr, int to, int color) {
			super();
			this.fr = fr;
			this.to = to;
			this.color = color;
		}

		@Override
		public int compareTo(Edge o) {
			return Integer.compare(color, o.color);
		}

	}

	int[] parent;

	int get(int x) {
		return parent[x] == x ? x : (parent[x] = get(parent[x]));
	}

	void unite(int x, int y) {
		x = get(x);
		y = get(y);
		if (x != y) {
			parent[x] = y;
		}
	}

	int qSz;
	int[] q;
	int[] bigId;
	int[] answer;
	ArrayList<Integer>[] all;
	ArrayList<Integer>[] qu;
	int[]fr;
	int[] to;
	int[] bigs;
	int[][] cnt;

	void upd() {
		for (int i = 0; i < qSz; i++) {
			int v = q[i];
			int root = get(v);
			if (bigId[v] == -1) {
				for (int curQ : qu[v]) {
					int another = fr[curQ] + to[curQ] - v;
					if (get(another) == root) {
						answer[curQ]++;
					}
				}
			}
			all[root].add(v);
		}
		for (int i = 0; i < bigs.length; i++) {
			int v = bigs[i];
			int root = get(v);
			for (int x : all[root])
				if (x != v && bigId[x] != -1) {
					cnt[i][bigId[x]]++;
				}
		}
		for (int i = 0; i < qSz; i++) {
			int v = q[i];
			int root = get(v);
			all[root].clear();
		}
		for (int i = 0; i < qSz; i++) {
			parent[q[i]] = q[i];
		}
	}

	void solve() {
		int n = in.nextInt();
		int m = in.nextInt();
		Edge[] allE = new Edge[m];
		for (int i = 0; i < m; i++) {
			allE[i] = new Edge(in.nextInt() - 1, in.nextInt() - 1, in.nextInt());
		}
		final int BIG = 444;
		int[] colors = new int[n];
		for (Edge e : allE) {
			colors[e.fr]++;
			colors[e.to]++;
		}
		bigId = new int[n];
		int cntBig = 0;
		Arrays.fill(bigId, -1);
		for (int i = 0; i < n; i++) {
			if (colors[i] >= BIG) {
				bigId[i] = cntBig++;
			}
		}
		bigs = new int[cntBig];
		for (int i = 0; i < n; i++) {
			if (bigId[i] != -1) {
				bigs[bigId[i]] = i;
			}
		}
		int qq = in.nextInt();
		fr = new int[qq];
		to = new int[qq];
		for (int i = 0; i < qq; i++) {
			fr[i] = in.nextInt() - 1;
			to[i] = in.nextInt() - 1;
		}
		answer = new int[qq];
		qu = new ArrayList[n];
		for (int i = 0; i < n; i++) {
			qu[i] = new ArrayList<>();
		}
		for (int i = 0; i < qq; i++) {
			if (bigId[fr[i]] == -1 || bigId[to[i]] == -1) {
				if (colors[fr[i]] < colors[to[i]]) {
					qu[fr[i]].add(i);
				} else {
					qu[to[i]].add(i);
				}
			}
		}
		Arrays.sort(allE);
		int lastColor = -1;
		q = new int[n];
		int[] used = new int[n];
		parent = new int[n];
		cnt = new int[cntBig][cntBig];
		for (int i = 0; i < n; i++) {
			parent[i] = i;
		}
		int time = 0;
		qSz = 0;
		all = new ArrayList[m + 1];
		for (int i = 0; i < all.length; i++) {
			all[i] = new ArrayList<>();
		}
		for (Edge e : allE) {
			if (e.color != lastColor) {
				upd();
				time++;
				qSz = 0;
			}
			if (used[e.fr] != time) {
				used[e.fr] = time;
				q[qSz++] = e.fr;
			}
			if (used[e.to] != time) {
				used[e.to] = time;
				q[qSz++] = e.to;
			}
			unite(e.fr, e.to);
			lastColor = e.color;
		}
		upd();
		for (int i = 0; i < qq; i++) {
			if (bigId[fr[i]] != -1 && bigId[to[i]] != -1) {
				answer[i] = cnt[bigId[fr[i]]][bigId[to[i]]];
			}
		}
		for (int ans : answer) {
			out.println(ans);
		}
	}

	void runIO() {

		in = new FastScanner(System.in);
		out = new PrintWriter(System.out);

		solve();

		out.close();
	}

	void run() {
		try {
			in = new FastScanner(new File("test.in"));
			out = new PrintWriter(new File("test.out"));

			solve();

			out.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
	}

	class FastScanner {
		BufferedReader br;
		StringTokenizer st;

		public FastScanner(File f) {
			try {
				br = new BufferedReader(new FileReader(f));
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
		}

		public FastScanner(InputStream f) {
			br = new BufferedReader(new InputStreamReader(f));
		}

		String next() {
			while (st == null || !st.hasMoreTokens()) {
				String s = null;
				try {
					s = br.readLine();
				} catch (IOException e) {
					e.printStackTrace();
				}
				if (s == null)
					return null;
				st = new StringTokenizer(s);
			}
			return st.nextToken();
		}

		boolean hasMoreTokens() {
			while (st == null || !st.hasMoreTokens()) {
				String s = null;
				try {
					s = br.readLine();
				} catch (IOException e) {
					e.printStackTrace();
				}
				if (s == null)
					return false;
				st = new StringTokenizer(s);
			}
			return true;
		}

		int nextInt() {
			return Integer.parseInt(next());
		}

		long nextLong() {
			return Long.parseLong(next());
		}

		double nextDouble() {
			return Double.parseDouble(next());
		}
	}

	public static void main(String[] args) {
		new CF().runIO();
	}
}


import java.io.*;
import java.util.*;

public class Main {
  public static class Pair implements Comparable<Pair>{
    int a, b;
    public Pair(int a, int b) {
      this.a = a;
      this.b = b;
    }
    @Override
    public int compareTo(Pair p) {
      if (p.a == this.a && p.b == this.b)
        return 0;
      else
        return Integer.compare(p.a, this.a);
    }
    public int compare(Pair p1, Pair p2) {
      return p1.compareTo(p2);
    }
    @Override
    public boolean equals(Object a) {
      if (this == a) return true;
      if (a == null) return false;
      if (getClass() != a.getClass())
        return false;
      Pair b = (Pair)a;
      if (this.a != b.a || this.b != b.b)
        return false;
      return true;
    }
    @Override
    public int hashCode() {
      return Objects.hash(a, b);
    }
  }
  public static PrintWriter out;
  public static int[] parent;
  public static Map<Integer, Integer> colors[];
  public static void main(String[] args) {
    MyScanner sc = new MyScanner();
    out = new PrintWriter(new BufferedOutputStream(System.out));
    int n = sc.nextInt();
    int m = sc.nextInt();
    colors = new HashMap[n + 1];
    parent = new int[m + 1];
    for (int i = 0; i <= n; i++) {
      colors[i] = new HashMap<Integer, Integer>();
    }
    for (int i = 1; i <= m; i++)
      parent[i] = i;
    for (int i = 1; i <= m; i++) {
      int a = sc.nextInt();
      int b = sc.nextInt();
      int c = sc.nextInt();
      int prevA = 0;
      int prevB = 0;
      Map<Integer, Integer> aMap = colors[a];
      if (aMap.containsKey(c)) {
        prevA = aMap.get(c);
      }
      Map<Integer, Integer> bMap = colors[b];
      if (bMap.containsKey(c)) {
        prevB = bMap.get(c);
      }
      aMap.put(c, i);
      bMap.put(c, i);
      if (prevA > 0)
        merge(prevA, i);
      if (prevB > 0)
        merge(prevB, i);
    }
    int Q = sc.nextInt();
    Map<Pair, Integer> ans = new HashMap<>();
    for (int i = 0; i < Q; i++) {
      int a = sc.nextInt();
      int b = sc.nextInt();
      int ret = 0;
      if (ans.containsKey(new Pair(a, b))) {
        ret = ans.get(new Pair(a, b));
      } else {
        Map<Integer, Integer> aMap = colors[a];
        Map<Integer, Integer> bMap = colors[b];
        if (aMap.size() > bMap.size()) {
          Map<Integer, Integer> cMap = aMap;
          aMap = bMap;
          bMap = cMap;
        }
        for (Map.Entry<Integer, Integer> entry : aMap.entrySet()) {
          int c = entry.getKey();
          int v1 = entry.getValue();
          if (bMap.containsKey(c)) {
            int v2 = bMap.get(c);
            if (find(v1) == find(v2))
              ret += 1;

          }
        }
        ans.put(new Pair(a, b), ret);
      }
      out.println(ret);
    }
    out.close();
  }

  public static int find(int p) {
    return parent[p] = (p == parent[p] ? p : find(parent[p]));
  }
  public static Random rand = new Random();
  public static void merge(int p, int q) {
    //parent[find(p)] = parent[find(q)];
    p = find(p);
    q = find(q);
    if (rand.nextBoolean())
      parent[p] = q;
    else
      parent[q] = p;
  }

  public static class MyScanner {
    BufferedReader br;
    StringTokenizer st;

    public MyScanner() {
       br = new BufferedReader(new InputStreamReader(System.in));
    }

    public boolean hasNext() {
      try {
        boolean a = br.ready();
        return a;
      } catch (IOException e) {
        return false;
      }
    }

    public String next() {
      while (st == null || !st.hasMoreElements()) {
        try {
          st = new StringTokenizer(br.readLine());
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
      return st.nextToken();
    }

    public int nextInt() {
      return Integer.parseInt(next());
    }

    public long nextLong() {
      return Long.parseLong(next());
    }

    public double nextDouble() {
      return Double.parseDouble(next());
    }

    public char nextChar() {
      return next().charAt(0);
    }

    public String nextLine() {
      String str = "";
      try {
         str = br.readLine();
      } catch (IOException e) {
         e.printStackTrace();
      }
      return str;
    }
  }
}


import java.io.*;
import java.util.*;

public class Main {
  public static PrintWriter out;
  public static int[] parent;
  public static Map<Integer, Integer> colors[];
  public static void main(String[] args) {
    MyScanner sc = new MyScanner();
    out = new PrintWriter(new BufferedOutputStream(System.out));
    int n = sc.nextInt();
    int m = sc.nextInt();
    colors = new HashMap[n + 1];
    parent = new int[m + 1];
    for (int i = 0; i <= n; i++) {
      colors[i] = new HashMap<Integer, Integer>();
    }
    for (int i = 1; i <= m; i++)
      parent[i] = i;
    for (int i = 1; i <= m; i++) {
      int a = sc.nextInt();
      int b = sc.nextInt();
      int c = sc.nextInt();
      int prevA = 0;
      int prevB = 0;
      Map<Integer, Integer> aMap = colors[a];
      if (aMap.containsKey(c)) {
        prevA = aMap.get(c);
      }
      Map<Integer, Integer> bMap = colors[b];
      if (bMap.containsKey(c)) {
        prevB = bMap.get(c);
      }
      aMap.put(c, i);
      bMap.put(c, i);
      if (prevA > 0)
        merge(prevA, i);
      if (prevB > 0)
        merge(prevB, i);
    }
    int Q = sc.nextInt();
    for (int i = 0; i < Q; i++) {
      int a = sc.nextInt();
      int b = sc.nextInt();
      int ret = 0;
      Map<Integer, Integer> aMap = colors[a];
      Map<Integer, Integer> bMap = colors[b];
      for (Map.Entry<Integer, Integer> entry : aMap.entrySet()) {
        int c = entry.getKey();
        int v1 = entry.getValue();
        if (bMap.containsKey(c)) {
          int v2 = bMap.get(c);
          if (find(v1) == find(v2))
            ret += 1;
        }
      }
      out.println(ret);
    }
    out.close();
  }

  public static int find(int p) {
    return parent[p] = (p == parent[p] ? p : find(parent[p]));
  }

  public static void merge(int p, int q) {
    parent[find(p)] = parent[find(q)];
  }

  public static class MyScanner {
    BufferedReader br;
    StringTokenizer st;

    public MyScanner() {
       br = new BufferedReader(new InputStreamReader(System.in));
    }

    public boolean hasNext() {
      try {
        boolean a = br.ready();
        return a;
      } catch (IOException e) {
        return false;
      }
    }

    public String next() {
      while (st == null || !st.hasMoreElements()) {
        try {
          st = new StringTokenizer(br.readLine());
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
      return st.nextToken();
    }

    public int nextInt() {
      return Integer.parseInt(next());
    }

    public long nextLong() {
      return Long.parseLong(next());
    }

    public double nextDouble() {
      return Double.parseDouble(next());
    }

    public char nextChar() {
      return next().charAt(0);
    }

    public String nextLine() {
      String str = "";
      try {
         str = br.readLine();
      } catch (IOException e) {
         e.printStackTrace();
      }
      return str;
    }
  }
}


import java.io.*;
import java.util.*;

public class Main {
  public static PrintWriter out;
  public static int[] parent;
  public static Map<Integer, Integer> colors[];
  public static void main(String[] args) {
    MyScanner sc = new MyScanner();
    out = new PrintWriter(new BufferedOutputStream(System.out));
    int n = sc.nextInt();
    int m = sc.nextInt();
    colors = new HashMap[n + 1];
    parent = new int[m + 1];
    for (int i = 0; i <= n; i++) {
      colors[i] = new HashMap<Integer, Integer>();
    }
    for (int i = 1; i <= m; i++)
      parent[i] = i;
    for (int i = 1; i <= m; i++) {
      int a = sc.nextInt();
      int b = sc.nextInt();
      int c = sc.nextInt();
      int prevA = 0;
      int prevB = 0;
      Map<Integer, Integer> aMap = colors[a];
      if (aMap.containsKey(c)) {
        prevA = aMap.get(c);
      }
      Map<Integer, Integer> bMap = colors[b];
      if (bMap.containsKey(c)) {
        prevB = bMap.get(c);
      }
      aMap.put(c, i);
      bMap.put(c, i);
      if (prevA > 0)
        merge(prevA, i);
      if (prevB > 0)
        merge(prevB, i);
    }
    int Q = sc.nextInt();
    for (int i = 0; i < Q; i++) {
      int a = sc.nextInt();
      int b = sc.nextInt();
      int ret = 0;
      Map<Integer, Integer> aMap = colors[a];
      Map<Integer, Integer> bMap = colors[b];
      for (Map.Entry<Integer, Integer> entry : aMap.entrySet()) {
        int c = entry.getKey();
        int v = entry.getValue();
        if (bMap.containsKey(c)) {
          if (parent[v] == parent[bMap.get(c)])
            ret += 1;
        }
      }
      out.println(ret);
    }
    out.close();
  }

  public static int find(int p) {
    return parent[p] = (p == parent[p] ? p : find(parent[p]));
  }

  public static void merge(int p, int q) {
    parent[find(p)] = parent[find(q)];
  }

  public static class MyScanner {
    BufferedReader br;
    StringTokenizer st;

    public MyScanner() {
       br = new BufferedReader(new InputStreamReader(System.in));
    }

    public boolean hasNext() {
      try {
        boolean a = br.ready();
        return a;
      } catch (IOException e) {
        return false;
      }
    }

    public String next() {
      while (st == null || !st.hasMoreElements()) {
        try {
          st = new StringTokenizer(br.readLine());
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
      return st.nextToken();
    }

    public int nextInt() {
      return Integer.parseInt(next());
    }

    public long nextLong() {
      return Long.parseLong(next());
    }

    public double nextDouble() {
      return Double.parseDouble(next());
    }

    public char nextChar() {
      return next().charAt(0);
    }

    public String nextLine() {
      String str = "";
      try {
         str = br.readLine();
      } catch (IOException e) {
         e.printStackTrace();
      }
      return str;
    }
  }
}


import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.BufferedWriter;
import java.util.InputMismatchException;
import java.util.ArrayList;
import java.util.HashMap;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.HashSet;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 * @author ilyakor
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        OutputWriter out = new OutputWriter(outputStream);
        TaskD solver = new TaskD();
        solver.solve(1, in, out);
        out.close();
    }
}

class TaskD {
    int gen = 1;
    int[] genMark;
    int[] parent;

    public void solve(int testNumber, InputReader in, OutputWriter out) {
        int n = in.nextInt();
        int m = in.nextInt();
        ArrayList<ii>[] edges = new ArrayList[m];
        for (int i = 0; i < m; ++i)
            edges[i] = new ArrayList<>();
        for (int i = 0; i < m; ++i) {
            int x = in.nextInt() - 1;
            int y = in.nextInt() - 1;
            int c = in.nextInt() - 1;
            edges[c].add(new ii(x, y));
        }

        HashSet<Integer>[] marks = new HashSet[n];
        for (int i = 0; i < n; ++i)
            marks[i] = new HashSet<>();
        gen = 1;
        genMark = new int[n];
        parent = new int[n];
        int currentMark = 1;
        for (int i = 0; i < m; ++i) {
            ++gen;
            HashSet<Integer> touched = new HashSet<>();
            for (ii edge : edges[i]) {
                int x = edge.first;
                int y = edge.second;
                touched.add(x);
                touched.add(y);
                uni(x, y);
            }

            HashMap<Integer, Integer> markIndex = new HashMap<>();
            for (int x : touched) {
                int comp = get(x);
                if (!markIndex.containsKey(comp)) {
                    markIndex.put(comp, currentMark);
                    currentMark++;
                }
                marks[x].add(markIndex.get(comp));
            }
        }

        HashMap<ii, Integer> queryCache = new HashMap<>();
        int q = in.nextInt();
        for (int i = 0; i < q; ++i) {
            int x = in.nextInt() - 1;
            int y = in.nextInt() - 1;
            if ((marks[x].size() > marks[y].size()) || (marks[x].size() == marks[y].size() && x > y)) {
                int t = x;
                x = y;
                y = t;
            }
            ii key = new ii(x, y);
            if (queryCache.containsKey(key)) {
                out.printLine(queryCache.get(key));
                continue;
            }

            int res = calc(marks[x], marks[y]);
            queryCache.put(key, res);
            out.printLine(res);
        }
    }

    private int calc(HashSet<Integer> a, HashSet<Integer> b) {
        int res = 0;
        for (int x : a)
            if (b.contains(x))
                ++res;
        return res;
    }

    void uni(int x, int y) {
        x = get(x);
        y = get(y);
        if (x == y) return;
        if ((((x * 43) ^ (y + 21)) >> 3) % 2 == 0) {
            parent[x] = y;
        } else {
            parent[y] = x;
        }
    }

    int get(int x) {
        if (genMark[x] != gen) {
            genMark[x] = gen;
            parent[x] = x;
        }
        if (parent[x] == x)
            return x;
        parent[x] = get(parent[x]);
        return parent[x];
    }
}

class InputReader {
    private InputStream stream;
    private byte[] buffer = new byte[10000];
    private int cur;
    private int count;

    public InputReader(InputStream stream) {
        this.stream = stream;
    }

    public static boolean isSpace(int c) {
        return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
    }

    public int read() {
        if (count == -1) {
            throw new InputMismatchException();
        }
        try {
            if (cur >= count) {
                cur = 0;
                count = stream.read(buffer);
                if (count <= 0)
                    return -1;
            }
        } catch (IOException e) {
            throw new InputMismatchException();
        }
        return buffer[cur++];
    }

    public int readSkipSpace() {
        int c;
        do {
            c = read();
        } while (isSpace(c));
        return c;
    }

    public int nextInt() {
        int sgn = 1;
        int c = readSkipSpace();
        if (c == '-') {
            sgn = -1;
            c = read();
        }
        int res = 0;
        do {
            if (c < '0' || c > '9') {
                throw new InputMismatchException();
            }
            res = res * 10 + c - '0';
            c = read();
        } while (!isSpace(c));
        res *= sgn;
        return res;
    }

}

class OutputWriter {
    private final PrintWriter writer;

    public OutputWriter(OutputStream outputStream) {
        writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));
    }

    public OutputWriter(Writer writer) {
        this.writer = new PrintWriter(writer);
    }

    public void print(Object... objects) {
        for (int i = 0; i < objects.length; i++) {
            if (i != 0) {
                writer.print(' ');
            }
            writer.print(objects[i]);
        }
    }

    public void printLine(Object... objects) {
        print(objects);
        writer.println();
    }

    public void close() {
        writer.close();
    }

}

class ii implements Comparable<ii> {
    public int first;
    public int second;

    public ii() {
    }

    public ii(int first, int second) {
        this.first = first;
        this.second = second;
    }

    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        ii ii = (ii) o;

        if (first != ii.first) return false;
        if (second != ii.second) return false;

        return true;
    }

    public int hashCode() {
        int result = first;
        result = 31 * result + second;
        return result;
    }

    public int compareTo(ii o) {
        if (first != o.first) {
            return first < o.first ? -1 : 1;
        }
        if (second != o.second) {
            return second < o.second ? -1 : 1;
        }
        return 0;
    }

}


import java.awt.Point;
import java.io.*;
import static java.lang.Math.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import static java.math.BigInteger.*;
import java.util.*;
import static java.util.Arrays.*;
import static java.lang.Character.*;
import static java.lang.Math.*;
import static java.math.BigInteger.*;
import static java.util.Arrays.*;
import java.awt.Point;

//<editor-fold defaultstate="collapsed" desc="Main">
public class Main implements Runnable {

    // https://netbeans.org/kb/73/java/editor-codereference_ru.html#display
    static boolean oj;

    @Override
    public void run() {
        try {
            Locale.setDefault(Locale.US);
        } catch (Exception e) {
        }
        oj = true;
        try {
            oj = System.getProperty("MYLOCAL") == null;
        } catch (Exception e) {
        }
//
        if (oj) {
            sc = new FastScanner(new InputStreamReader(System.in));
            out = new PrintWriter(new OutputStreamWriter(System.out));
        } else {
            try {
                sc = new FastScanner(new FileReader("input.txt"));
//                sc = new FastScanner(new FileReader("C:\\Users\\Igor\\Desktop\\e\\tests\\02"));
                out = new PrintWriter(new FileWriter("output.txt"));
            } catch (IOException e) {
                MLE();
            }
        }
        Solver s = new Solver();
        s.sc = sc;
        s.out = out;

        s.solve();
        if (!oj) {
            err.println("Time: " + (System.currentTimeMillis() - timeBegin) / 1e3);
            err.printf("Mem: %d\n", (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) >> 20);
        }
        out.flush();
    }

    public static void exit() {
        err.println("Time: " + (System.currentTimeMillis() - timeBegin) / 1e3);
        err.printf("Mem: %d\n", (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) >> 20);
        out.flush();
        out.close();
        System.exit(0);
    }

    public static void MLE() {
        int[][] arr = new int[1024 * 1024][];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = new int[1024 * 1024];
        }
    }

    public static void main(String[] args) {
        new Main().run();
        //new Thread(null, new Main(), "myThread", 100 * 1024 * 1024).start();
    }

    static long timeBegin = System.currentTimeMillis();
    static FastScanner sc;
    static PrintWriter out;
    static PrintStream err = System.err;
}
    //</editor-fold>

//<editor-fold defaultstate="collapsed" desc="FastScanner">
class FastScanner {

    BufferedReader br;
    StringTokenizer st;

    FastScanner(InputStreamReader reader) {
        br = new BufferedReader(reader);
        st = new StringTokenizer("");
    }

    String next() {
        while (!st.hasMoreElements()) {
            try {
                st = new StringTokenizer(br.readLine());
            } catch (Exception ex) {
                return null;
            }
        }
        return st.nextToken();
    }

    int nextInt() {
        return Integer.parseInt(next());
    }

    long nextLong() {
        return Long.parseLong(next());
    }

    double nextDouble() {
        return Double.parseDouble(next());
    }

    String nextLine() {
        try {
            return br.readLine();
        } catch (IOException ex) {
            return null;
        }
    }
}
//</editor-fold>

class Solver {

    void aser(boolean OK) {
        if (!OK) {
            Main.MLE();
//            for(;;);
        }
    }

    FastScanner sc;
    PrintWriter out;
    static PrintStream err = System.err;

    void solve() {
        int n, m;
        ArrayList<Rib>[] ribs;
        TreeSet<Integer>[] idLeader;

        n = sc.nextInt();
        m = sc.nextInt();
        ribs = new ArrayList[m + 1];
        for (int c = 1; c <= m; c++) {
            ribs[c] = new ArrayList<>(1);
        }
        for (int iter = 0; iter < m; iter++) {
            Rib r = new Rib(sc.nextInt(), sc.nextInt());
            int c = sc.nextInt();
            ribs[c].add(r);
        }

        idLeader = new TreeSet[n + 1];
        for (int v = 1; v <= n; v++) {
            idLeader[v] = new TreeSet<>();
        }
        for (int c = 1, id = 0; c <= m; c++) {
            DSU dsu = new DSU(ribs[c]);
            HashMap<Integer, Integer> idLd = new HashMap<>();
            for (Map.Entry<Integer, Integer> e : dsu.map.entrySet()) {
                int v = e.getKey();
                int idV = e.getValue();
                int leader = dsu.getParent(idV);
                if (!idLd.containsKey(leader)) {
                    idLd.put(leader, id++);
                }
                int idLeade = idLd.get(leader);
                idLeader[v].add(idLeade);
            }
        }

        int Q = sc.nextInt();
        HashMap<String, Integer> answers = new HashMap<>();
        for (int iter = 0; iter < Q; iter++) {
            int a = sc.nextInt();
            int b = sc.nextInt();
            if (idLeader[a].size() > idLeader[b].size()
                    || idLeader[a].size() == idLeader[b].size() && a > b) {
                int t = a;
                a = b;
                b = t;
            }
            String hashQ = a + "," + b;
            Integer get = answers.get(hashQ);
            if (get != null) {
                out.println(get);
                continue;
            }

            int curAns = 0;
            for (Integer x : idLeader[a]) {
                if (idLeader[b].contains(x)) {
                    ++curAns;
                }
            }
            out.println(curAns);

            answers.put(hashQ, curAns);
        }
    }
}

final class DSU {

    TreeMap<Integer, Integer> map;
    int[] p;
    int[] sz;

    public DSU(ArrayList<Rib> arr) {
        map = new TreeMap<>();
        for (Rib r : arr) {
            if (!map.containsKey(r.a)) {
                map.put(r.a, map.size());
            }
            if (!map.containsKey(r.b)) {
                map.put(r.b, map.size());
            }
        }
        p = new int[map.size()];
        sz = new int[map.size()];
        for (int i = 0; i < p.length; i++) {
            p[i] = i;
        }
        for (int i = 0; i < sz.length; i++) {
            sz[i] = 1;
        }
        for (Rib r : arr) {
            int a = map.get(r.a);
            int b = map.get(r.b);
            unit(a, b);
        }
    }

    int getParent(int v) {
        if (p[v] == v) {
            return v;
        }
        return p[v] = getParent(p[v]);
    }

    void unit(int a, int b) {
        a = getParent(a);
        b = getParent(b);
        if (sz[a] < sz[b]) {
            int t = a;
            a = b;
            b = t;
        }
        p[b] = a;
        sz[a] += sz[b];
    }

}

class Rib {

    int a, b;

    public Rib(int a, int b) {
        this.a = a;
        this.b = b;
    }

}


import java.awt.Point;
import java.io.*;
import static java.lang.Math.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import static java.math.BigInteger.*;
import java.util.*;
import static java.util.Arrays.*;
import static java.lang.Character.*;
import static java.lang.Math.*;
import static java.math.BigInteger.*;
import static java.util.Arrays.*;
import java.awt.Point;

//<editor-fold defaultstate="collapsed" desc="Main">
public class Main implements Runnable {

    // https://netbeans.org/kb/73/java/editor-codereference_ru.html#display
    static boolean oj;

    @Override
    public void run() {
        try {
            Locale.setDefault(Locale.US);
        } catch (Exception e) {
        }
        oj = true;
        try {
            oj = System.getProperty("MYLOCAL") == null;
        } catch (Exception e) {
        }
//
        if (oj) {
            sc = new FastScanner(new InputStreamReader(System.in));
            out = new PrintWriter(new OutputStreamWriter(System.out));
        } else {
            try {
                sc = new FastScanner(new FileReader("input.txt"));
//                sc = new FastScanner(new FileReader("C:\\Users\\Igor\\Desktop\\e\\tests\\02"));
                out = new PrintWriter(new FileWriter("output.txt"));
            } catch (IOException e) {
                MLE();
            }
        }
        Solver s = new Solver();
        s.sc = sc;
        s.out = out;

        s.solve();
        if (!oj) {
            err.println("Time: " + (System.currentTimeMillis() - timeBegin) / 1e3);
            err.printf("Mem: %d\n", (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) >> 20);
        }
        out.flush();
    }

    public static void exit() {
        err.println("Time: " + (System.currentTimeMillis() - timeBegin) / 1e3);
        err.printf("Mem: %d\n", (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) >> 20);
        out.flush();
        out.close();
        System.exit(0);
    }

    public static void MLE() {
        int[][] arr = new int[1024 * 1024][];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = new int[1024 * 1024];
        }
    }

    public static void main(String[] args) {
        new Main().run();
        //new Thread(null, new Main(), "myThread", 100 * 1024 * 1024).start();
    }

    static long timeBegin = System.currentTimeMillis();
    static FastScanner sc;
    static PrintWriter out;
    static PrintStream err = System.err;
}
    //</editor-fold>

//<editor-fold defaultstate="collapsed" desc="FastScanner">
class FastScanner {

    BufferedReader br;
    StringTokenizer st;

    FastScanner(InputStreamReader reader) {
        br = new BufferedReader(reader);
        st = new StringTokenizer("");
    }

    String next() {
        while (!st.hasMoreElements()) {
            try {
                st = new StringTokenizer(br.readLine());
            } catch (Exception ex) {
                return null;
            }
        }
        return st.nextToken();
    }

    int nextInt() {
        return Integer.parseInt(next());
    }

    long nextLong() {
        return Long.parseLong(next());
    }

    double nextDouble() {
        return Double.parseDouble(next());
    }

    String nextLine() {
        try {
            return br.readLine();
        } catch (IOException ex) {
            return null;
        }
    }
}
//</editor-fold>

class Solver {

    void aser(boolean OK) {
        if (!OK) {
            Main.MLE();
//            for(;;);
        }
    }

    FastScanner sc;
    PrintWriter out;
    static PrintStream err = System.err;

    void solve() {
        int n, m;
        ArrayList<Rib>[] ribs;
        ArrayList<DSU>[] cntDSU;

        n = sc.nextInt();
        m = sc.nextInt();
        ribs = new ArrayList[m + 1];
        for (int c = 1; c <= m; c++) {
            ribs[c] = new ArrayList<>(1);
        }
        for (int iter = 0; iter < m; iter++) {
            Rib r = new Rib(sc.nextInt(), sc.nextInt());
            int c = sc.nextInt();
            ribs[c].add(r);
        }

        cntDSU = new ArrayList[n + 1];
        for (int v = 1; v <= n; v++) {
            cntDSU[v] = new ArrayList<>(1);
        }
        for (int c = 1; c <= m; c++) {
            DSU dsu = new DSU(ribs[c]);
            for (Integer v : dsu.map.keySet()) {
                cntDSU[v].add(dsu);
            }
        }

        int Q = sc.nextInt();
        HashMap<String, Integer> answers = new HashMap<>();
        for (int iter = 0; iter < Q; iter++) {
            int a = sc.nextInt();
            int b = sc.nextInt();
            if (cntDSU[a].size() > cntDSU[b].size()) {
                int t = a;
                a = b;
                b = t;
            }
            Integer get = answers.get(a + "," + b);
            if (get != null) {
                out.println(get);
                continue;
            }

            int curAns = 0;
            for (DSU dsu : cntDSU[a]) {
                if (dsu.isConnected(a, b)) {
                    ++curAns;
                }
            }
            out.println(curAns);

            answers.put(a + "," + b, curAns);
            answers.put(b + "," + a, curAns);
        }
    }
}

final class DSU {

    TreeMap<Integer, Integer> map;
    int[] p;
    int[] sz;

    boolean isConnected(Integer a, Integer b) {
        a = map.get(a);
        b = map.get(b);
        if (a == null || b == null) {
            return false;
        }
        return getParent(a) == getParent(b);
    }

    public DSU(ArrayList<Rib> arr) {
        map = new TreeMap<>();
        for (Rib r : arr) {
            if (!map.containsKey(r.a)) {
                map.put(r.a, map.size());
            }
            if (!map.containsKey(r.b)) {
                map.put(r.b, map.size());
            }
        }
        p = new int[map.size()];
        sz = new int[map.size()];
        for (int i = 0; i < p.length; i++) {
            p[i] = i;
        }
        for (int i = 0; i < sz.length; i++) {
            sz[i] = 1;
        }
        for (Rib r : arr) {
            int a = map.get(r.a);
            int b = map.get(r.b);
            unit(a, b);
        }
    }

    int getParent(int v) {
        if (p[v] == v) {
            return v;
        }
        return p[v] = getParent(p[v]);
    }

    void unit(int a, int b) {
        a = getParent(a);
        b = getParent(b);
        if (sz[a] < sz[b]) {
            int t = a;
            a = b;
            b = t;
        }
        p[b] = a;
        sz[a] += sz[b];
    }

}

class Rib {

    int a, b;

    public Rib(int a, int b) {
        this.a = a;
        this.b = b;
    }

}


import java.awt.Point;
import java.io.*;
import static java.lang.Math.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import static java.math.BigInteger.*;
import java.util.*;
import static java.util.Arrays.*;
import static java.lang.Character.*;
import static java.lang.Math.*;
import static java.math.BigInteger.*;
import static java.util.Arrays.*;
import java.awt.Point;

//<editor-fold defaultstate="collapsed" desc="Main">
public class Main implements Runnable {

    // https://netbeans.org/kb/73/java/editor-codereference_ru.html#display
    static boolean oj;

    @Override
    public void run() {
        try {
            Locale.setDefault(Locale.US);
        } catch (Exception e) {
        }
        oj = true;
        try {
            oj = System.getProperty("MYLOCAL") == null;
        } catch (Exception e) {
        }
//
        if (oj) {
            sc = new FastScanner(new InputStreamReader(System.in));
            out = new PrintWriter(new OutputStreamWriter(System.out));
        } else {
            try {
                sc = new FastScanner(new FileReader("input.txt"));
//                sc = new FastScanner(new FileReader("C:\\Users\\Igor\\Desktop\\e\\tests\\02"));
                out = new PrintWriter(new FileWriter("output.txt"));
            } catch (IOException e) {
                MLE();
            }
        }
        Solver s = new Solver();
        s.sc = sc;
        s.out = out;

        s.solve();
        if (!oj) {
            err.println("Time: " + (System.currentTimeMillis() - timeBegin) / 1e3);
            err.printf("Mem: %d\n", (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) >> 20);
        }
        out.flush();
    }

    public static void exit() {
        err.println("Time: " + (System.currentTimeMillis() - timeBegin) / 1e3);
        err.printf("Mem: %d\n", (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) >> 20);
        out.flush();
        out.close();
        System.exit(0);
    }

    public static void MLE() {
        int[][] arr = new int[1024 * 1024][];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = new int[1024 * 1024];
        }
    }

    public static void main(String[] args) {
        new Main().run();
        //new Thread(null, new Main(), "myThread", 100 * 1024 * 1024).start();
    }

    static long timeBegin = System.currentTimeMillis();
    static FastScanner sc;
    static PrintWriter out;
    static PrintStream err = System.err;
}
    //</editor-fold>

//<editor-fold defaultstate="collapsed" desc="FastScanner">
class FastScanner {

    BufferedReader br;
    StringTokenizer st;

    FastScanner(InputStreamReader reader) {
        br = new BufferedReader(reader);
        st = new StringTokenizer("");
    }

    String next() {
        while (!st.hasMoreElements()) {
            try {
                st = new StringTokenizer(br.readLine());
            } catch (Exception ex) {
                return null;
            }
        }
        return st.nextToken();
    }

    int nextInt() {
        return Integer.parseInt(next());
    }

    long nextLong() {
        return Long.parseLong(next());
    }

    double nextDouble() {
        return Double.parseDouble(next());
    }

    String nextLine() {
        try {
            return br.readLine();
        } catch (IOException ex) {
            return null;
        }
    }
}
//</editor-fold>

class Solver {

    void aser(boolean OK) {
        if (!OK) {
            Main.MLE();
//            for(;;);
        }
    }

    FastScanner sc;
    PrintWriter out;
    static PrintStream err = System.err;

    void solve() {
        int n, m;
        ArrayList<Rib>[] ribs;
        ArrayList<DSU>[] cntDSU;

        n = sc.nextInt();
        m = sc.nextInt();
        ribs = new ArrayList[m + 1];
        for (int c = 1; c <= m; c++) {
            ribs[c] = new ArrayList<>(1);
        }
        for (int iter = 0; iter < m; iter++) {
            Rib r = new Rib(sc.nextInt(), sc.nextInt(), sc.nextInt());
            ribs[r.c].add(r);
        }

        cntDSU = new ArrayList[n + 1];
        for (int v = 1; v <= n; v++) {
            cntDSU[v] = new ArrayList<>(1);
        }
        for (int c = 1; c <= m; c++) {
            DSU dsu = new DSU(ribs[c]);
            for (Integer v : dsu.map.keySet()) {
                cntDSU[v].add(dsu);
            }
        }

        int Q = sc.nextInt();
        Map<String,Integer> answers = new HashMap<>();
        for (int iter = 0; iter < Q; iter++) {
            int a = sc.nextInt();
            int b = sc.nextInt();
            if (cntDSU[a].size() > cntDSU[b].size()) {
                int t = a;
                a = b;
                b = t;
            }
            Integer get = answers.get(a+","+b);
            if (get != null) {
                out.println(get);
                continue;
            }

            int curAns = 0;
            for (DSU dsu : cntDSU[a]) {
                if (dsu.isConnected(a, b)) {
                    ++curAns;
                }
            }
            out.println(curAns);

            answers.put(a+","+b, curAns);
            answers.put(b+","+a, curAns);
        }
    }
}

final class DSU {

    Map<Integer, Integer> map;
    int[] p;
    int[] sz;

    boolean isConnected(int a, int b){
        if ( !map.containsKey(a) || !map.containsKey(b) ) {
            return false;
        }
        a = map.get(a);
        b = map.get(b);
        return getParent(a) == getParent(b);
    }

    public DSU(ArrayList<Rib> arr) {
        map = new TreeMap<>();
        for (Rib r : arr) {
            if (!map.containsKey(r.a)) {
                map.put(r.a, map.size());
            }
            if (!map.containsKey(r.b)) {
                map.put(r.b, map.size());
            }
        }
        p = new int[map.size()];
        sz = new int[map.size()];
        for (int i = 0; i < p.length; i++) {
            p[i] = i;
        }
        for (int i = 0; i < sz.length; i++) {
            sz[i] = 1;
        }
        for (Rib r : arr) {
            int a = map.get(r.a);
            int b = map.get(r.b);
            unit(a, b);
        }
    }

    int getParent(int v) {
        if (p[v] == v) {
            return v;
        }
        return p[v] = getParent(p[v]);
    }

    void unit(int a, int b) {
        a = getParent(a);
        b = getParent(b);
        if (sz[a] < sz[b]) {
            unit(b, a);
        } else {
            p[b] = a;
            sz[a] += sz[b];
        }
    }

}

class Rib {

    int a, b, c;

    public Rib(int a, int b, int c) {
        this.a = a;
        this.b = b;
        this.c = c;
    }

}