Problem:
MathJax.Hub.Config({ tex2jax: { inlineMath: [["$","$"], ["\\(","\\)"]], processEscapes: true }});

部活動調査

A 高校の生徒会長である明は、A 高校の生徒がどの部活動に所属しているかを調査することにした。A高校には 1 から N の番号が付けられた N 人の生徒と、1 から M の番号が付けられた M 種類の部活動がある。各部活動に人数制限はなく、0 人の部活動もありえる。ただし、A 高校の校則では生徒はひとつの部活動までしか所属できない。生徒は全員この校則を守っている。

明は生徒会員に調査を依頼し、各行が次のいずれかであるような K 行の記録を入手した。

生徒 a と生徒 b は同じ部活動に所属している。

生徒 c は部活動 x に所属している。

しかし、この記録には誰かが校則違反になってしまうような矛盾があるかもしれない。明は１行目から順に見ていき、矛盾があると判断できる最初の行を探すことにした。

K 行の記録が与えられたとき、矛盾があると判断できる最初の行の番号を求めるプログラムを作成せよ。

Input

入力は以下の形式で与えられる。

N M K
record1
record2
:
recordK

１行目に生徒の人数 N (1 ≤ N ≤ 100000)、部活動の種類の数 M (1 ≤ M ≤ 100000)、記録の行数 K (1 ≤ K ≤ 200000) が与えられる。続く K 行に記録の各行 recordi が、以下のいずれかの形式で与えられる。

1 a b

または

2 c x

先頭の数字が「1」のとき、生徒 a (1 ≤ a ≤ N) と生徒 b (1 ≤ b ≤ N) が同じ部活動に所属していることを示す。ただし、a ≠ b である。

先頭の数字が「2」のとき、生徒 c (1 ≤ c ≤ N) が部活動 x (1 ≤ x ≤ M) に所属していることを示す。

Output

矛盾があると判断できる最初の行の番号を１行に出力する。見つからない場合は 0 を１行に出力する。

Sample Input 1

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

Sample Output 1

4

Sample Input 2

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

Sample Output 2

0

Sample Input 3

3 2 2
1 1 2
2 1 1

Sample Output 3

0

Solution in C++14 (judge verdict: Accepted)

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using VI = vector<int>;
using VL = vector<ll>;
#define FOR(i,a,n) for(int (i)=(a);(i)<(n);(i)++)
#define eFOR(i,a,n) for(int (i)=(a);(i)<=(n);(i)++)
#define rFOR(i,a,n) for(int (i)=(n)-1;(i)>=(a);(i)--)
#define erFOR(i,a,n) for(int (i)=(n);(i)>=(a);(i)--)
#define SORT(i) sort((i).begin(),(i).end())
#define rSORT(i,a) sort((i).begin(),(i).end(),(a))
#define all(i) (i).begin(),(i).end()
constexpr ll INF = 1000000000;
constexpr ll LLINF = 1LL << 60;
constexpr ll mod = 1000000007;
constexpr ll MOD = 998244353;
template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; }return 0; }
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; }return 0; }
inline void init() { cin.tie(nullptr); cout.tie(nullptr); cin.tie(nullptr); ios::sync_with_stdio(false); cout << fixed << setprecision(15); }

class unionfind {
    VI par, rank;
    int forest_num;
public:
    unionfind(int n) : par(n), rank(n, 1) {
        forest_num = n;
        for (int i = 0; i < n; i++)par[i] = i;
    }
    void init(int n) {
        par.clear(); par.resize(n);
        rank.clear(); rank.resize(n, 1);
        forest_num = n;
        for (int i = 0; i < n; i++)par[i] = i;
    }
    int root(int x) {
        if (par[x] == x)return x;
        return par[x] = root(par[x]);
    }
    int size(int x) {
        if (par[x] == x)return rank[x];
        return size(par[x]);
    }
    void unite(int x, int y) {
        int rx = root(x);
        int ry = root(y);
        if (rx == ry)return;
        if (rank[rx] < rank[ry]) {
            par[rx] = ry;
            rank[ry] += rank[rx];
        }
        else {
            par[ry] = rx;
            rank[rx] += rank[ry];
        }
        forest_num--;
    }
    bool same(int x, int y) {
        return root(x) == root(y);
    }
    int fnum() {
        return forest_num;
    }
};

int main() {
    init();

    int n, m, k;
    cin >> n >> m >> k;

    unionfind uf(n);
    VI club(n, -1);
    int num, a, b, ans = INF;
    eFOR(i, 1, k) {
        cin >> num >> a >> b;
        a--, b--;
        int ar = uf.root(a), br = uf.root(b);
        if (num == 1){
            if (!uf.same(a, b)) {
                uf.unite(a, b);
                int nextr = uf.root(a);
                if (club[ar] != club[br]) {
                    if (club[ar] == -1)club[nextr] = club[br];
                    else if (club[br] == -1)club[nextr] = club[ar];
                    else chmin(ans, i);
                }
            }
        }
        else {
            if (club[ar] == -1)club[ar] = b;
            else if (club[ar] != b)chmin(ans, i);
        }
    }
    cout << ans % INF << "\n";
}