Problem: Akira, the student council president of A High School, decided to investigate which club activities the A High School students belong to. A High School has N students numbered 1 to N and M types of club activities numbered 1 to M. There is no limit to the number of people in each club activity, and there can be 0 club activities. However, according to the school rules of A High School, students can only belong to one club activity. All students follow this school rule.

Akira asked student members to investigate and obtained records for line K, such as each line being one of the following:

* Student a and student b belong to the same club activities.
* Student c belongs to club activity x.



However, there may be a contradiction in this record that would cause someone to violate school rules. Akira decided to look at the first line in order and look for the first line that could be judged to be inconsistent.

Create a program that finds the number of the first line that can be determined to be inconsistent given a record of K lines.



Input

The input is given in the following format.


NMK
record1
record2
::
recordK


The first line gives the number of students N (1 ≤ N ≤ 100000), the number of club activity types M (1 ≤ M ≤ 100000), and the number of recorded lines K (1 ≤ K ≤ 200000). Each line of record, recordi, is given in the following K lines in one of the following formats:


1 a b


Or


2 c x


When the first digit is "1", it indicates that student a (1 ≤ a ≤ N) and student b (1 ≤ b ≤ N) belong to the same club activity. However, a ≠ b.

When the first digit is "2", it indicates that student c (1 ≤ c ≤ N) belongs to club activity x (1 ≤ x ≤ M).

Output

Output the number of the first line that can be determined to be inconsistent on one line. If not found, output 0 on one line.

Examples

Input

3 2 5
1 1 2
1 2 3
2 1 1
2 3 2
2 2 1


Output

4


Input

3 2 4
1 1 2
2 1 1
2 3 2
2 2 1


Output

0


Input

3 2 2
1 1 2
2 1 1


Output

0

Solution (in CPP):

Solution:
/*#include <iostream>
#include <cmath>
#include <vector>
#include <algorithm>
#include <array>
#include <vector>
#include <deque>
#include <set>
#include <map>
#include <string>
#include <stack>
#include <queue>
#include <unordered_map>
#include <unordered_set>
*/
 
#include <bits/stdc++.h>
using namespace std;
 
// #define int long long
#define pb push_back
#define mp make_pair
#define F first
#define S second
#define FOR(i,a,b) for(int (i)=(a);(i)<(b);(i)++)
#define REP(i,n) FOR(i,0,n)
#define ALL(a) (a).begin(),(a).end()
#define RALL(a) (a).rbegin(),(a).rend()
#define SORT(c) sort((c).begin(),(c).end())
 
typedef long long ll;
const ll INF = LLONG_MAX - 100;
const ll mod = 1e9 + 7;
const int MAX_N = 5e5 + 5;
int dx[] = { -1LL,0,1LL,0 }, dy[] = { 0,1LL,0,-1LL };
vector<ll> prime;
 
ll inv[MAX_N], fac[MAX_N];
 
template <class T = ll> T in() { T x; cin >> x; return (x); }
inline ll GCD(ll a, ll b) { ll c; while (b != 0) { c = a % b; a = b; b = c; }return a; }
inline ll LCM(ll a, ll b) { return a * b / GCD(a, b); }
inline ll POW(ll a, ll b) { ll c = 1LL; while (b > 0) { if (b & 1LL) { c = a * c%mod; }a = a * a%mod; b >>= 1LL; }return c; }
inline void _nCr() { fac[0] = 1LL; for (int i = 1LL; i < MAX_N; i++) { fac[i] = fac[i - 1LL] * i%mod; }for (int i = 0; i < MAX_N; i++) { inv[i] = POW(fac[i], mod - 2); } }
inline ll nCr(ll n, ll r) { return (fac[n] * inv[r] % mod)*inv[n - r] % mod; }
inline void PRI(ll n) { bool a[n + 1LL]; for (int i = 0; i < n + 1LL; i++) { a[i] = 1LL; }for (int i = 2; i < n + 1LL; i++) { if (a[i]) { prime.pb(i); ll b = i; while (b <= n) { a[b] = 0; b += i; } } } }
 
typedef pair<int, pair<int, int>> edge;
 
class UnionFind {
public:
	vector<int> par;
	vector<int> color;
	UnionFind(int N) { par = vector<int>(N, -1LL); color = vector<int>(N,-1);}
	int find(int x);
	ll size(int x);
	bool unite(int x, int y);
	bool same(int x, int y);
};
 
 
 
class Kruskal {
private:
	UnionFind *uf;
	vector<edge> e;
public:
	vector<edge> mst;
	Kruskal(int N) { uf = new UnionFind(N); }
	void add(int x, int y, ll z);
	void run();
};
 
 
 
//----UnionFind-------------------------------
int UnionFind::find(int x) {
	if (par[x] < 0) return x;
	else return par[x] = find(par[x]);
}
 
ll UnionFind::size(int x) {
	return -par[find(x)];
}
 
bool UnionFind::unite(int x, int y) {
	x = find(x);
	y = find(y);
 	if (x == y) return true;
	//大きい方に小さい方をくっ付ける
	if (size(x) < size(y)) swap(x, y);
	par[x] += par[y];
	par[y] = x;
	if (color[x] != -1 && color[y] != -1 && color[x] != color[y]) return false;
	else color[x] = max(color[x],color[y]);
	return true;
}
 
bool UnionFind::same(int x, int y) {
	x = find(x);
	y = find(y);
	return x == y;
}
 
 
 
//----Kruskal-------------------------------
void Kruskal::add(int x, int y, ll z) {
	//x < y
	if (x > y) swap(x, y);
	e.push_back({ z,{x,y} });
}
 
void Kruskal::run() {
	sort(e.begin(), e.end());
	e.erase(unique(e.begin(), e.end()), e.end());
	for (auto x : e) {
		if (uf->same(x.second.first, x.second.second)) {
			continue;
		}
		else {
			mst.push_back(x);
			uf->unite(x.second.first, x.second.second);
		}
	}
}

signed main() {
	int n,m,k; cin >> n >> m >> k;
	UnionFind uf(n);
	REP (i,k) {
		int num; cin >> num;
		if (num == 1) {
			int a,b; cin >> a >> b;
			if (!uf.unite(a-1,b-1)) {cout << i+1 << endl; return 0;}
		} else {
			int c,x; cin >> c >> x;
			if (uf.color[uf.find(c-1)] == -1) uf.color[uf.find(c-1)] = x;
			else if (uf.color[uf.find(c-1)] != x) {cout << i+1 << endl; return 0;}
		}
	}
	cout << 0 << endl;
}