Problem:
テトラ姫のパズル
パレス王国のテトラ姫は無類のパズル好きとして知られており，最近は自身が考案した「テトラパズル」に熱中している．
これは，正三角形のマスを敷き詰めたボードと，テトラブロックと呼ばれる 4 枚の正三角形のパネルからなる正四面体のブロックを使ったパズルである．
パズルの目的は，ボード上のすべてのテトラブロックを以下の条件をみたすように展開することである．
展開されたテトラブロックが，置かれていたマスおよび，それぞれに指定された異なる 2 つのマスを覆っている
どのマスも，2 つ以上のパネルで覆われていない
図F-1はテトラパズルの問題例および，その解答例である．
★のマスと●のマスにテトラブロックが置かれており，それぞれが☆のマスと○のマスを覆うように指定されている．
解答例において，横線が引かれたマスは★のマスに置かれていたテトラブロックを展開して覆ったマス，縦線のマスは●のマスに置かれたテトラブロックで覆ったマスである．
図 F-1: テトラパズルの問題例(左)および解答例(右)
図F-2は，上図の問題例における無効な解答例である．
左の例では★のマスの真上のマスが2つのパネルで覆われており，右の例ではそれぞれがテトラブロックを展開して得られる形状でないため，答えとしては認められない．
図 F-2: 無効な解答例
テトラ姫はパズルの面白さを多くの人に知ってもらうべく，来たる夏の祭典に向けてパズルの問題集を作った．
そして，王国で二番目のパズル好きとして姫から信頼を置かれているあなたは，問題集のチェック担当に任命された．
さて，チェック作業を進めていたあなたは困った事に気が付いた．
問題集には解が存在しないパズルが含まれているようなのだ．
なるべく姫の作ったパズルを尊重したいと考えたあなたは，解が存在しないパズルについて，どれか 1 個のテトラブロックをそのテトラブロックが覆うべきマスの情報ごと削除することで，パズルを解けるものに変えることにした．
姫から言い渡されたチェックの締切りまではあと3時間しかない．
問題集を見なおして，手早く修正を済ませてしまおう．
Input
入力は複数のデータセットから構成される．
各データセットの形式は次の通りである．
n
x
1a
y
1a
x
1b
y
1b
x
1c
y
1c
x
2a
y
2a
x
2b
y
2b
x
2c
y
2c
...
x
na
y
na
x
nb
y
nb
x
nc
y
nc
n (2 ≤ n ≤ 5,000) はボードに置かれたテトラブロックの数を表す整数である．
各テトラブロックには 1 から n の番号が割り当てられている．
続く n 行は，それぞれ 1 個のスペースで区切られた 6 個の整数からなる．
(x
ia
, y
ia
) は i 番目のテトラブロックが置かれているマスの座標を表し，(x
ib
, y
ib
) および，(x
ic
, y
ic
) は，それぞれ i 番目のテトラブロックを展開した時に覆うべきマスの座標を表す．
与えられる x 座標および y 座標の絶対値は 20,000 以下と仮定して良い．
また，与えられる座標は全て互いに異なると仮定して良い．
すなわち，同じマスに 2 個以上のテトラブロックが置かれる事や，テトラブロックが置かれているマスが覆うべきマスとして指定される事や，覆うべきマスが重複して指定される事はない．
各マスには図F-3のように座標が割り当てられている．
図 F-3: マスに割り当てられた座標
n=0 は入力の終わりを示す．これはデータセットには含めない．
Output
各データセットについて，テトラブロックを除くことなくパズルが解ける場合は Valid をそれぞれ 1 行に出力しなさい．
テトラブロックを 1 個だけ除くことでパズルが解けるようになる場合は Remove を 1 行に出力し，続けて除くことでパズルが解けるようになるテトラブロックの番号を小さいものから順にそれぞれ 1 行に出力しなさい．
2 個以上のテトラブロックを除かないとパズルが解けるようにならない場合は Invalid を1行に出力しなさい．
Sample Input
3
2 3 2 2 2 1
2 0 1 -1 2 -1
-2 -1 -1 -1 -2 0
6
-1 0 1 0 0 -1
-2 -1 -3 -2 -4 -2
2 -1 2 0 1 -1
4 -2 3 -2 3 -1
1 1 0 1 -1 1
-3 -1 -1 -1 -2 0
5
-1 2 0 2 1 2
-3 1 -2 1 -2 2
-2 0 -2 -1 -3 0
1 -1 0 -1 -1 -1
1 0 2 0 2 -1
4
-2 0 -2 -1 -3 -1
-1 -1 0 -1 1 -1
2 -1 2 0 3 -1
-1 0 0 0 1 0
5
-2 1 3 -1 2 1
-5 2 -5 3 -4 2
-2 -1 0 -1 -3 -1
4 2 5 2 5 3
1 -1 2 -1 -1 -1
0
以下の図はそれぞれサンプルの配置を示している．
図 F-4: 1番目のサンプル
図 F-5: 2番目のサンプル
図 F-6: 3番目のサンプル
図 F-7: 4番目のサンプル
図 F-8: 5番目のサンプル
Output for Sample Input
Remove
1
Remove
2
6
Valid
Remove
1
2
3
4
Invalid

Submitted solutions:

code_snippet: #include <iostream>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;
#pragma warning (disable: 4996)

const vector<vector<pair<int, int>>> Orientation = {
	vector<pair<int, int>> { make_pair(0,  0), make_pair(1,  0), make_pair(2,  0), make_pair(3,  0) },
	vector<pair<int, int>> { make_pair(-1, 0), make_pair(0,  0), make_pair(1,  0), make_pair(2,  0) },
	vector<pair<int, int>> { make_pair(0,  0), make_pair(1,  0), make_pair(1,  1), make_pair(2,  1) },
	vector<pair<int, int>> { make_pair(0, -1), make_pair(0,  0), make_pair(1,  0), make_pair(1,  1) },
	vector<pair<int, int>> { make_pair(0,  0), make_pair(-1,  0), make_pair(-1,  1), make_pair(-2,  1) },
	vector<pair<int, int>> { make_pair(0, -1), make_pair(0,  0), make_pair(-1,  0), make_pair(-1,  1) },
	vector<pair<int, int>> { make_pair(0,  0), make_pair(0, -1), make_pair(-1, -1), make_pair(1, -1) },
	vector<pair<int, int>> { make_pair(0,  0), make_pair(0, -1), make_pair(-1,  0), make_pair(1,  0) }
};

// ============================================================== Flow Library ==============================================================
struct Edge {
	int to, cap, rev;
};

class MaxFlow {
public:
	int size_ = 0;
	int banned = -1;
	vector<Edge> G[30009];
	bool Used[30009];

	void init(int sz) {
		size_ = sz;
	}

	void add_edge(int u, int v, int c) {
		G[u].push_back(Edge{ v, c, (int)G[v].size() });
		G[v].push_back(Edge{ u, 0, (int)G[u].size() - 1 });
	}

	int dfs(int pos, int goal, int f) {
		if (pos == goal) return f;
		Used[pos] = true;

		// DFS
		for (int i = 0; i < G[pos].size(); i++) {
			if (G[pos][i].cap == 0) continue;
			if (Used[G[pos][i].to] == true) continue;
			int F = dfs(G[pos][i].to, goal, min(f, G[pos][i].cap));
			if (F == 0) continue;
			G[pos][i].cap -= F;
			G[G[pos][i].to][G[pos][i].rev].cap += F;
			return F;
		}
		return 0;
	}

	int max_flow(int u, int v) {
		int Return = 0;
		while (true) {
			for (int i = 0; i < size_; i++) Used[i] = false;
			if (banned != -1) Used[banned] = true;
			int ret = dfs(u, v, 100000000);
			if (ret == 0) break;
			Return += ret;
		}
		return Return;
	}
};

// ============================================================== Main Part ==============================================================
int N;
int X1[30009], Y1[30009], X2[30009], Y2[30009], X3[30009], Y3[30009];
int Count[30009];
vector<pair<int, int>> Cand[30009];
vector<int> List[30009];
vector<Edge> Moto[30009];

void Initialize() {
	for (int i = 0; i < 30009; i++) {
		X1[i] = 0; Y1[i] = 0; X2[i] = 0; Y2[i] = 0; X3[i] = 0; Y3[i] = 0;
		Count[i] = 0;
		List[i].clear();
		Cand[i].clear();
	}
}

vector<pair<int, int>> GetCandidate(int ax, int ay, int bx, int by, int cx, int cy) {
	vector<pair<int, int>> Base;
	for (int i = -3; i <= 3; i++) {
		for (int j = -3; j <= 3; j++) {
			Base.push_back(make_pair(ax + i, ay + j));
			Base.push_back(make_pair(bx + i, by + j));
			Base.push_back(make_pair(cx + i, cy + j));
		}
	}
	sort(Base.begin(), Base.end());
	Base.erase(unique(Base.begin(), Base.end()), Base.end());

	// Enumerate Candidates
	vector<pair<int, int>> Cand;
	for (int i = 0; i < Base.size(); i++) {
		if (abs(Base[i].first + Base[i].second) % 2 != 0) continue;
		for (int j = 0; j < Orientation.size(); j++) {
			int cnt = 0;
			pair<int, int> rem = make_pair(-1, -1);
			for (int k = 0; k < 4; k++) {
				int px = Base[i].first + Orientation[j][k].first;
				int py = Base[i].second + Orientation[j][k].second;
				if (make_pair(ax, ay) == make_pair(px, py)) cnt += 1;
				else if (make_pair(bx, by) == make_pair(px, py)) cnt += 1;
				else if (make_pair(cx, cy) == make_pair(px, py)) cnt += 1;
				else rem = make_pair(px, py);
			}
			if (cnt != 3) continue;
			Cand.push_back(rem);
		}
	}
	sort(Cand.begin(), Cand.end());
	Cand.erase(unique(Cand.begin(), Cand.end()), Cand.end());
	return Cand;
}

int main() {
	while (true) {
		// Step 1. Input
		Initialize();
		scanf("%d", &N); if (N == 0) break;
		for (int i = 0; i < N; i++) scanf("%d%d%d%d%d%d", &X1[i], &Y1[i], &X2[i], &Y2[i], &X3[i], &Y3[i]);

		// Step 2. Get Candidates
		vector<pair<int, int>> Zahyou;
		for (int i = 0; i < N; i++) {
			Cand[i] = GetCandidate(X1[i], Y1[i], X2[i], Y2[i], X3[i], Y3[i]);
			for (pair<int, int> j : Cand[i]) Zahyou.push_back(j);
		}
		sort(Zahyou.begin(), Zahyou.end());
		Zahyou.erase(unique(Zahyou.begin(), Zahyou.end()), Zahyou.end());

		// Step 3. Counting
		for (int i = 0; i < N; i++) {
			int pos1 = lower_bound(Zahyou.begin(), Zahyou.end(), make_pair(X1[i], Y1[i])) - Zahyou.begin();
			int pos2 = lower_bound(Zahyou.begin(), Zahyou.end(), make_pair(X2[i], Y2[i])) - Zahyou.begin();
			int pos3 = lower_bound(Zahyou.begin(), Zahyou.end(), make_pair(X3[i], Y3[i])) - Zahyou.begin();
			if (pos1 < Zahyou.size() && Zahyou[pos1] == make_pair(X1[i], Y1[i])) Count[pos1] += 1;
			if (pos2 < Zahyou.size() && Zahyou[pos2] == make_pair(X2[i], Y2[i])) Count[pos2] += 1;
			if (pos3 < Zahyou.size() && Zahyou[pos3] == make_pair(X3[i], Y3[i])) Count[pos3] += 1;
		}

		// Step 4. Make Graph
		MaxFlow Z;
		Z.init(N + Zahyou.size() + 2);
		for (int i = 0; i < N; i++) {
			for (int j = 0; j < Cand[i].size(); j++) {
				int pos1 = lower_bound(Zahyou.begin(), Zahyou.end(), Cand[i][j]) - Zahyou.begin();
				if (Count[pos1] >= 1) List[pos1].push_back(i);
				if (Count[pos1] == 0) Z.add_edge(i, pos1 + N, 1);
			}
		}
		for (int i = 0; i < N; i++) Z.add_edge(N + Zahyou.size() + 0, i, 1);
		for (int i = 0; i < Zahyou.size(); i++) Z.add_edge(N + i, N + Zahyou.size() + 1, 1);

		// Step 5. Get Flow
		int Answer = Z.max_flow(N + Zahyou.size(), N + Zahyou.size() + 1);
		if (Answer == N) {
			printf("Valid\n");
			continue;
		}

		// Step 6. Corner Case
		for (int i = 0; i < N + Zahyou.size() + 2; i++) Moto[i] = Z.G[i];
		vector<int> Vector;
		vector<pair<int, int>> Reverse(N, make_pair(-1, -1));
		for (int i = 0; i < Z.G[N + Zahyou.size()].size(); i++) {
			if (Z.G[N + Zahyou.size()][i].cap == 1) continue;
			for (int j = 0; j < Z.G[i].size(); j++) {
				int nex = Z.G[i][j].to;
				if (nex < N || nex >= N + Zahyou.size()) continue;
				if (Z.G[i][j].cap == 1) continue;
				for (int k = 0; k < Z.G[nex].size(); k++) {
					if (Z.G[nex][k].to == N + Zahyou.size() + 1) Reverse[i] = make_pair(nex, k);
				}
			}
		}

		// Brute Force
		for (int i = 0; i < N; i++) {
			int Current = Answer;
			if (Reverse[i] != make_pair(-1, -1)) Current -= 1;

			// Add Edge
			vector<int> Added;
			int pos1 = lower_bound(Zahyou.begin(), Zahyou.end(), make_pair(X1[i], Y1[i])) - Zahyou.begin();
			int pos2 = lower_bound(Zahyou.begin(), Zahyou.end(), make_pair(X2[i], Y2[i])) - Zahyou.begin();
			int pos3 = lower_bound(Zahyou.begin(), Zahyou.end(), make_pair(X3[i], Y3[i])) - Zahyou.begin();
			if (pos1 < Zahyou.size() && Zahyou[pos1] == make_pair(X1[i], Y1[i])) Added.push_back(pos1);
			if (pos2 < Zahyou.size() && Zahyou[pos2] == make_pair(X2[i], Y2[i])) Added.push_back(pos2);
			if (pos3 < Zahyou.size() && Zahyou[pos3] == make_pair(X3[i], Y3[i])) Added.push_back(pos3);
			int adds = 0;
			for (int j : Added) {
				for (int k : List[j]) Z.add_edge(k, j + N, 1);
				adds += List[j].size();
			}
			if (adds == 0 && Current <= N - 3) continue;
			if (Reverse[i] != make_pair(-1, -1)) Z.G[Reverse[i].first][Reverse[i].second].cap += 1;
			if (Reverse[i] != make_pair(-1, -1)) Z.G[Z.G[Reverse[i].first][Reverse[i].second].to][Z.G[Reverse[i].first][Reverse[i].second].rev].cap -= 1;

			// Get New Flow
			Z.banned = i;
			int ret = Z.max_flow(N + Zahyou.size(), N + Zahyou.size() + 1);
			Current += ret;
			if (Current == N - 1) Vector.push_back(i);
			if (adds >= 1 || ret >= 1) {
				for (int j = 0; j < N + Zahyou.size() + 2; j++) Z.G[j] = Moto[j];
			}
			else {
				if (Reverse[i] != make_pair(-1, -1)) Z.G[Reverse[i].first][Reverse[i].second].cap -= 1;
				if (Reverse[i] != make_pair(-1, -1)) Z.G[Z.G[Reverse[i].first][Reverse[i].second].to][Z.G[Reverse[i].first][Reverse[i].second].rev].cap += 1;
			}
		}

		// Step 7: Output
		if (Vector.size() >= 1) {
			printf("Remove\n");
			for (int i : Vector) printf("%d\n", i + 1);
		}
		else {
			printf("Invalid\n");
		}
	}
	return 0;
}
accuracy: 1
time_ms: 7490
memory_kb: 12640
final_rank: 20

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=998244353,MAX=300005,INF=1<<30;

// フローのみ

// from: https://gist.github.com/yosupo06/ddd51afb727600fd95d9d8ad6c3c80c9
// (based on AtCoder STL)

#ifndef ATCODER_INTERNAL_QUEUE_HPP
#define ATCODER_INTERNAL_QUEUE_HPP 1
#include <vector>
namespace atcoder {
    namespace internal {
        template <class T> struct simple_queue {
            std::vector<T> payload;
            int pos = 0;
            void reserve(int n) { payload.reserve(n); }
            int size() const { return int(payload.size()) - pos; }
            bool empty() const { return pos == int(payload.size()); }
            void push(const T& t) { payload.push_back(t); }
            T& front() { return payload[pos]; }
            void clear() {
                payload.clear();
                pos = 0;
            }
            void pop() { pos++; }
        };
    }  // namespace internal
}  // namespace atcoder
#endif  // ATCODER_INTERNAL_QUEUE_HPP

#ifndef ATCODER_MAXFLOW_HPP
#define ATCODER_MAXFLOW_HPP 1
#include <algorithm>
#include <cassert>
#include <limits>
#include <queue>
#include <vector>
namespace atcoder {
    template <class Cap> struct mf_graph {
    public:
        mf_graph() : _n(0) {}
        mf_graph(int n) : _n(n), g(n) {}
        int add_edge(int from, int to, Cap cap) {
            assert(0 <= from && from < _n);
            assert(0 <= to && to < _n);
            assert(0 <= cap);
            int m = int(pos.size());
            pos.push_back({from, int(g[from].size())});
            g[from].push_back(_edge{to, int(g[to].size()), cap});
            g[to].push_back(_edge{from, int(g[from].size()) - 1, 0});
            return m;
        }
        struct edge {
            int from, to;
            Cap cap, flow;
        };
        edge get_edge(int i) {
            int m = int(pos.size());
            assert(0 <= i && i < m);
            auto _e = g[pos[i].first][pos[i].second];
            auto _re = g[_e.to][_e.rev];
            return edge{pos[i].first, _e.to, _e.cap + _re.cap, _re.cap};
        }
        std::vector<edge> edges() {
            int m = int(pos.size());
            std::vector<edge> result;
            for (int i = 0; i < m; i++) {
                result.push_back(get_edge(i));
            }
            return result;
        }
        void change_edge(int i, Cap new_cap, Cap new_flow) {
            int m = int(pos.size());
            assert(0 <= i && i < m);
            assert(0 <= new_flow && new_flow <= new_cap);
            auto& _e = g[pos[i].first][pos[i].second];
            auto& _re = g[_e.to][_e.rev];
            _e.cap = new_cap - new_flow;
            _re.cap = new_flow;
        }
        Cap flow(int s, int t) {
            return flow(s, t, std::numeric_limits<Cap>::max());
        }
        Cap flow(int s, int t, Cap flow_limit) {
            assert(0 <= s && s < _n);
            assert(0 <= t && t < _n);
            std::vector<int> level(_n), iter(_n);
            internal::simple_queue<int> que;
            auto bfs = [&]() {
                std::fill(level.begin(), level.end(), -1);
                level[s] = 0;
                que.clear();
                que.push(s);
                while (!que.empty()) {
                    int v = que.front();
                    que.pop();
                    for (auto e : g[v]) {
                        if (e.cap == 0 || level[e.to] >= 0) continue;
                        level[e.to] = level[v] + 1;
                        if (e.to == t) return;
                        que.push(e.to);
                    }
                }
            };
            auto dfs = [&](auto self, int v, Cap up) {
                if (v == s) return up;
                Cap res = 0;
                int level_v = level[v];
                for (int& i = iter[v]; i < int(g[v].size()); i++) {
                    _edge& e = g[v][i];
                    if (level_v <= level[e.to] || g[e.to][e.rev].cap == 0) continue;
                    Cap d =
                    self(self, e.to, std::min(up - res, g[e.to][e.rev].cap));
                    if (d <= 0) continue;
                    g[v][i].cap += d;
                    g[e.to][e.rev].cap -= d;
                    res += d;
                    if (res == up) break;
                }
                return res;
            };
            Cap flow = 0;
            while (flow < flow_limit) {
                bfs();
                if (level[t] == -1) break;
                std::fill(iter.begin(), iter.end(), 0);
                while (flow < flow_limit) {
                    Cap f = dfs(dfs, t, flow_limit - flow);
                    if (!f) break;
                    flow += f;
                }
            }
            return flow;
        }
        std::vector<bool> min_cut(int s) {
            std::vector<bool> visited(_n);
            internal::simple_queue<int> que;
            que.push(s);
            while (!que.empty()) {
                int p = que.front();
                que.pop();
                visited[p] = true;
                for (auto e : g[p]) {
                    if (e.cap && !visited[e.to]) {
                        visited[e.to] = true;
                        que.push(e.to);
                    }
                }
            }
            return visited;
        }
    private:
        int _n;
        struct _edge {
            int to, rev;
            Cap cap;
        };
        std::vector<std::pair<int, int>> pos;
        std::vector<std::vector<_edge>> g;
    };
}  // namespace atcoder
#endif  // ATCODER_MAXFLOW_HPP
#ifndef ATCODER_MINCOSTFLOW_HPP
#define ATCODER_MINCOSTFLOW_HPP 1
#include <algorithm>
#include <cassert>
#include <limits>
#include <queue>
#include <vector>
namespace atcoder {
    template <class Cap, class Cost> struct mcf_graph {
    public:
        mcf_graph() {}
        mcf_graph(int n) : _n(n), g(n) {}
        int add_edge(int from, int to, Cap cap, Cost cost) {
            assert(0 <= from && from < _n);
            assert(0 <= to && to < _n);
            int m = int(pos.size());
            pos.push_back({from, int(g[from].size())});
            g[from].push_back(_edge{to, int(g[to].size()), cap, cost});
            g[to].push_back(_edge{from, int(g[from].size()) - 1, 0, -cost});
            return m;
        }
        struct edge {
            int from, to;
            Cap cap, flow;
            Cost cost;
        };
        edge get_edge(int i) {
            int m = int(pos.size());
            assert(0 <= i && i < m);
            auto _e = g[pos[i].first][pos[i].second];
            auto _re = g[_e.to][_e.rev];
            return edge{
                pos[i].first, _e.to, _e.cap + _re.cap, _re.cap, _e.cost,
            };
        }
        std::vector<edge> edges() {
            int m = int(pos.size());
            std::vector<edge> result(m);
            for (int i = 0; i < m; i++) {
                result[i] = get_edge(i);
            }
            return result;
        }
        std::pair<Cap, Cost> flow(int s, int t) {
            return flow(s, t, std::numeric_limits<Cap>::max());
        }
        std::pair<Cap, Cost> flow(int s, int t, Cap flow_limit) {
            return slope(s, t, flow_limit).back();
        }
        std::vector<std::pair<Cap, Cost>> slope(int s, int t) {
            return slope(s, t, std::numeric_limits<Cap>::max());
        }
        std::vector<std::pair<Cap, Cost>> slope(int s, int t, Cap flow_limit) {
            assert(0 <= s && s < _n);
            assert(0 <= t && t < _n);
            assert(s != t);
            // variants (C = maxcost):
            // -(n-1)C <= dual[s] <= dual[i] <= dual[t] = 0
            // reduced cost (= e.cost + dual[e.from] - dual[e.to]) >= 0 for all edge
            std::vector<Cost> dual(_n, 0), dist(_n);
            std::vector<int> pv(_n), pe(_n);
            std::vector<bool> vis(_n);
            auto dual_ref = [&]() {
                std::fill(dist.begin(), dist.end(),
                          std::numeric_limits<Cost>::max());
                std::fill(pv.begin(), pv.end(), -1);
                std::fill(pe.begin(), pe.end(), -1);
                std::fill(vis.begin(), vis.end(), false);
                struct Q {
                    Cost key;
                    int to;
                    bool operator<(Q r) const { return key > r.key; }
                };
                std::priority_queue<Q> que;
                dist[s] = 0;
                que.push(Q{0, s});
                while (!que.empty()) {
                    int v = que.top().to;
                    que.pop();
                    if (vis[v]) continue;
                    vis[v] = true;
                    if (v == t) break;
                    // dist[v] = shortest(s, v) + dual[s] - dual[v]
                    // dist[v] >= 0 (all reduced cost are positive)
                    // dist[v] <= (n-1)C
                    for (int i = 0; i < int(g[v].size()); i++) {
                        auto e = g[v][i];
                        if (vis[e.to] || !e.cap) continue;
                        // |-dual[e.to] + dual[v]| <= (n-1)C
                        // cost <= C - -(n-1)C + 0 = nC
                        Cost cost = e.cost - dual[e.to] + dual[v];
                        if (dist[e.to] - dist[v] > cost) {
                            dist[e.to] = dist[v] + cost;
                            pv[e.to] = v;
                            pe[e.to] = i;
                            que.push(Q{dist[e.to], e.to});
                        }
                    }
                }
                if (!vis[t]) {
                    return false;
                }
                for (int v = 0; v < _n; v++) {
                    if (!vis[v]) continue;
                    // dual[v] = dual[v] - dist[t] + dist[v]
                    //         = dual[v] - (shortest(s, t) + dual[s] - dual[t]) + (shortest(s, v) + dual[s] - dual[v])
                    //         = - shortest(s, t) + dual[t] + shortest(s, v)
                    //         = shortest(s, v) - shortest(s, t) >= 0 - (n-1)C
                    dual[v] -= dist[t] - dist[v];
                }
                return true;
            };
            Cap flow = 0;
            Cost cost = 0, prev_cost = -1;
            std::vector<std::pair<Cap, Cost>> result;
            result.push_back({flow, cost});
            while (flow < flow_limit) {
                if (!dual_ref()) break;
                Cap c = flow_limit - flow;
                for (int v = t; v != s; v = pv[v]) {
                    c = std::min(c, g[pv[v]][pe[v]].cap);
                }
                for (int v = t; v != s; v = pv[v]) {
                    auto& e = g[pv[v]][pe[v]];
                    e.cap -= c;
                    g[v][e.rev].cap += c;
                }
                Cost d = -dual[s];
                flow += c;
                cost += c * d;
                if (prev_cost == d) {
                    result.pop_back();
                }
                result.push_back({flow, cost});
                prev_cost = d;
            }
            return result;
        }
    private:
        int _n;
        struct _edge {
            int to, rev;
            Cap cap;
            Cost cost;
        };
        std::vector<std::pair<int, int>> pos;
        std::vector<std::vector<_edge>> g;
    };
}  // namespace atcoder
#endif  // ATCODER_MINCOSTFLOW_HPP

vector<vector<pair<int,int>>> A;

bool check(vector<pair<int,int>> S){
    sort(all(S));
    for(int i=0;i+1<si(S);i++){
        if(S[i]==S[i+1]) return false;
    }
    for(auto a:A){
        bool ok=true;
        for(int i=0;i<si(S);i++){
            int s=S[i].fi-a[i].fi,t=S[i].se-a[i].se;
            if(abs(s+t)&1){
                ok=false;
                break;
            }
            int ss=S[0].fi-a[0].fi,tt=S[0].se-a[0].se;
            if(mp(s,t)!=mp(ss,tt)){
                ok=false;
                break;
            }
        }
        if(ok) return true;
    }
    return false;
}

int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    A.push_back({mp(0,0),mp(1,0),mp(2,0),mp(3,0)});
    A.push_back({mp(-1,0),mp(0,0),mp(1,0),mp(2,0)});
    A.push_back({mp(0,-1),mp(0,0),mp(1,-2),mp(1,-1)});
    A.push_back({mp(0,-1),mp(1,-2),mp(1,-1),mp(2,-2)});
    A.push_back({mp(0,-1),mp(0,0),mp(1,0),mp(1,1)});
    A.push_back({mp(0,0),mp(1,0),mp(1,1),mp(2,1)});
    A.push_back({mp(0,0),mp(1,0),mp(1,1),mp(2,0)});
    A.push_back({mp(-1,0),mp(0,-1),mp(0,0),mp(1,0)});
    
    while(1){
        int N;cin>>N;
        if(N==0) break;
        
        vector<vector<pair<int,int>>> P(N,vector<pair<int,int>>(3)),Q(N);
        vector<pair<int,int>> used,add;
        
        for(int i=0;i<N;i++){
            for(int j=0;j<3;j++){
                cin>>P[i][j].fi>>P[i][j].se;
                used.push_back(P[i][j]);
            }
        }
        sort(all(used));
        used.erase(unique(all(used)),used.end());
        
        for(int i=0;i<N;i++){
            for(int h=-3;h<=3;h++){
                for(int w=-3;w<=3;w++){
                    auto a=P[i];
                    a.push_back(mp(a[0].fi+h,a[0].se+w));
                    //if(binary_search(all(used),a.back())) continue;
                    if(check(a)){
                        Q[i].push_back(a.back());
                        add.push_back(a.back());
                    }
                }
            }
        }
        sort(all(add));
        add.erase(unique(all(add)),add.end());
        
        int M=si(add);
        
        atcoder::mf_graph<int> G(N+M+2);
        int s=N+M,t=N+M+1;
        
        map<pair<int,int>,int> MA;
        
        vector<vector<pair<int,int>>> L(N+M+2),R(N+M+2);
        
        for(int i=0;i<N;i++){
            G.add_edge(s,i,1);
            L[s].push_back(mp(i,i));
            R[i].push_back(mp(s,i));
        }
        
        for(int i=0;i<M;i++){
            G.add_edge(N+i,t,!binary_search(all(used),add[i]));
            L[N+i].push_back(mp(t,N+i));
            R[t].push_back(mp(N+i,N+i));
            //cout<<(!binary_search(all(used),add[i]))<<" ";
        }
        //cout<<endl;
        
        for(int i=0;i<N;i++){
            for(auto a:Q[i]){
                int x=lower_bound(all(add),a)-add.begin();
                int z=si(MA)+N+M;
                MA[mp(i,N+x)]=z;
                L[i].push_back(mp(N+x,z));
                R[N+x].push_back(mp(i,z));
                G.add_edge(i,N+x,1);
            }
        }
        
        int K=G.flow(s,t);
        
        if(K==N){
            cout<<"Valid\n";
            continue;
        }
        /*
        for(int i=0;i<N;i++){
            for(auto to:L[i]) cout<<to.fi<<" "<<to.se<<" ";
            cout<<"\n";
        }
        */
        //auto ee=G.edges();
        //for(int i=0;i<si(ee);i++) cout<<ee[i].from<<" "<<ee[i].to<<" "<<ee[i].cap<<" "<<ee[i].flow<<endl;
        
        auto cancel=[&](int id){
            auto e=G.get_edge(id);
            if(e.flow==0) return;
            K--;
            if(id<N){
                G.change_edge(id,1,0);
                int ne=-1;
                for(auto to:L[id]){
                    auto x=G.get_edge(to.se);
                    if(x.flow){
                        G.change_edge(to.se,1,0);
                        ne=to.fi;
                        break;
                    }
                }
                assert(ne!=-1);
                assert(N<=ne&&ne<N+M);
                G.change_edge(ne,1,0);
            }else{
                G.change_edge(id,1,0);
                int ne=-1;
                for(auto to:R[id]){
                    auto x=G.get_edge(to.se);
                    if(x.flow){
                        G.change_edge(to.se,1,0);
                        ne=to.fi;
                        break;
                    }
                }
                assert(ne!=-1);
                assert(0<=ne&&ne<N);
                G.change_edge(ne,1,0);
            }
        };
        
        vector<int> ans;
        
        for(int i=0;i<N;i++){
            auto e=G.get_edge(i);
            
            if(K<=N-5) continue;
            
            //cout<<i<<" "<<e.flow<<endl;
            
            if(e.flow==0){
                //cout<<3<<endl;
                
                //continue;
                for(int j=0;j<3;j++){
                    auto x=P[i][j];
                    if(binary_search(all(add),x)){
                        int xx=lower_bound(all(add),x)-add.begin();
                        G.change_edge(N+xx,1,0);
                    }
                }
                G.change_edge(i,0,0);
                K+=G.flow(s,t);
                if(K==N-1) ans.push_back(i);
                
                G.change_edge(i,1,0);
                
                for(int j=0;j<3;j++){
                    auto x=P[i][j];
                    if(binary_search(all(add),x)){
                        int xx=lower_bound(all(add),x)-add.begin();
                        int id=N+xx;
                        e=G.get_edge(id);
                        if(e.flow){
                            cancel(id);
                        }
                        G.change_edge(id,0,0);
                    }
                }
                
                //K+=G.flow(s,t);
            }else{
                //cout<<1<<endl;
                cancel(i);
                //cout<<2<<endl;
                for(int j=0;j<3;j++){
                    auto x=P[i][j];
                    if(binary_search(all(add),x)){
                        int xx=lower_bound(all(add),x)-add.begin();
                        //cout<<xx<<" ";
                        auto ee=G.get_edge(N+xx);
                        //cout<<ee.from<<" "<<ee.to<<" "<<ee.cap<<" "<<ee.flow<<endl;
                        G.change_edge(N+xx,1,0);
                    }
                    //cout<<endl;
                }
                //cout<<endl;
                G.change_edge(i,0,0);
                //cout<<G.flow(s,t)<<endl;
                K+=G.flow(s,t);
                if(K==N-1) ans.push_back(i);
                
                G.change_edge(i,1,0);
                
                for(int j=0;j<3;j++){
                    auto x=P[i][j];
                    if(binary_search(all(add),x)){
                        int xx=lower_bound(all(add),x)-add.begin();
                        int id=N+xx;
                        e=G.get_edge(id);
                        if(e.flow){
                            cancel(id);
                        }
                        G.change_edge(id,0,0);
                    }
                }
                
                //K+=G.flow(s,t);
            }
            
        }
        
        if(si(ans)){
            cout<<"Remove\n";
            for(int a:ans) cout<<a+1<<"\n";
        }else{
            cout<<"Invalid\n";
        }
    }
}
accuracy: 1
time_ms: 7700
memory_kb: 10516
final_rank: 19

code_snippet: #include <bits/stdc++.h>
using namespace std;
const int INF = 10000;
struct triangle{
  int x, y;
  triangle(){
  }
  triangle(int x, int y): x(x), y(y){
  }
  bool operator ==(triangle T){
    return x == T.x && y == T.y;
  }
  bool operator !=(triangle T){
    return x != T.x || y != T.y;
  }
  bool operator <(triangle T) const{
    return x < T.x || x == T.x && y < T.y;
  }
  triangle operator +(triangle T){
    return triangle(x + T.x, y + T.y);
  }
};
vector<triangle> D = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
vector<vector<vector<triangle>>> C = {{{{1, 0}, {2, 0}, {3, 0}}, {{1, 0}, {1, 1}, {2, 1}}, {{1, 0}, {1, 1}, {2, 0}}}, {{{1, 0}, {2, 0}, {3, 0}}, {{1, -1}, {1, 0}, {2, -1}}, {{0, 1}, {1, 1}, {1, 2}}, {{0, 1}, {1, -1}, {1, 0}}, {{1, -1}, {1, 0}, {2, 0}}}}; 
bool valid(vector<triangle> T){
  sort(T.begin(), T.end());
  int p = abs(T[0].x + T[0].y) % 2;
  int cnt = C[p].size();
  for (int i = 0; i < cnt; i++){
    bool ok = true;
    for (int j = 0; j < 3; j++){
      if (T[j + 1] != T[0] + C[p][i][j]){
        ok = false;
      }
    }
    if (ok){
      return true;
    }
  }
  return false;
}
struct dinic{
  struct edge{
    int to, cap, rev;
    edge(){
    }
    edge(int to, int cap, int rev): to(to), cap(cap), rev(rev){
    }
  };
  int N;
  vector<int> A, curr;
  vector<pair<int, int>> E;
  vector<edge> G;
  int S, T;
  int F = 0;
  dinic(int N, vector<int> C, int S, int T): N(N), S(S), T(T){
    A = vector<int>(N + 1);
    A[0] = 0;
    for (int i = 0; i < N; i++){
      A[i + 1] = A[i] + C[i];
    }
    curr = vector<int>(N, 0);
    G.resize(A[N]);
  }
  void add_edge(int u, int v){
    E.push_back(make_pair(u, A[u] + curr[u]));
    G[A[u] + curr[u]] = edge(v, 1, A[v] + curr[v]);
    G[A[v] + curr[v]] = edge(u, 0, A[u] + curr[u]);
    curr[u]++;
    curr[v]++;
  }
  int dfs(vector<int> &d, vector<int> &iter, int v, int t, int f){
    if (v == t){
      return f; 
    }
    while (iter[v] < A[v + 1]){
      int w = G[iter[v]].to;
      if (G[iter[v]].cap > 0 && d[v] < d[w]){
        int f2 = dfs(d, iter, w, t, min(f, G[iter[v]].cap));
        if (f2 > 0){
          G[iter[v]].cap -= f2;
          G[G[iter[v]].rev].cap += f2;
          return f2;
        }
      }
      iter[v]++;
    }
    return 0;
  }
  int flow(int s, int t, int M){
    int ans = 0;
    while (ans < M){
      vector<int> d(N, -1);
      d[s] = 0;
      queue<int> Q;
      Q.push(s);
      while (!Q.empty()){
        if (d[t] != -1){
          break;
        }
        int v = Q.front();
        Q.pop();
        for (int i = A[v]; i < A[v + 1]; i++){
          int w = G[i].to;
          if (G[i].cap > 0 && d[w] == -1){
            d[w] = d[v] + 1;
            Q.push(w);
          }
        }
      }
      if (d[t] == -1){
        break;
      }
      vector<int> iter(N);
      for (int i = 0; i < N; i++){
        iter[i] = A[i];
      }
      while (ans < M){
        int f = dfs(d, iter, s, t, M - ans);
        if (f == 0){
          break;
        }
        ans += f;
      }
    }
    return ans;
  }
  void update(){
    F += flow(S, T, INF);
  }
  void add_edge(int p){
    G[E[p].second].cap++;
  }
  void remove_edge(int p){
    if (G[E[p].second].cap > 0){
      G[E[p].second].cap--;
    } else {
      int u = E[p].first;
      int v = G[E[p].second].to;
      if (flow(u, v, 1) == 0){
        F--;
        flow(T, v, 1);
        flow(u, S, 1);
      }
    }
  }
};
int main(){
  while (true){
    int n;
    cin >> n;
    if (n == 0){
      break;
    }
    vector<vector<triangle>> T(n, vector<triangle>(3));
    for (int i = 0; i < n; i++){
      for (int j = 0; j < 3; j++){
        cin >> T[i][j].x >> T[i][j].y;
      }
    }
    vector<vector<triangle>> R(n);
    for (int i = 0; i < n; i++){
      vector<triangle> C;
      for (int j = 0; j < 3; j++){
        for (int k = 0; k < 4; k++){
          C.push_back(T[i][j] + D[k]);
        }
      }
      for (int j = 0; j < 12; j++){
        vector<triangle> T2 = T[i];
        T2.push_back(C[j]);
        if (valid(T2)){
          R[i].push_back(C[j]);
        }
      }
      sort(R[i].begin(), R[i].end());
      R[i].erase(unique(R[i].begin(), R[i].end()), R[i].end());
    }
    vector<triangle> R2;
    for (int i = 0; i < n; i++){
      int cnt = R[i].size();
      for (int j = 0; j < cnt; j++){
        R2.push_back(R[i][j]);
      }
    }
    sort(R2.begin(), R2.end());
    R2.erase(unique(R2.begin(),  R2.end()), R2.end());
    int m = R2.size();
    vector<vector<int>> A(n);
    vector<vector<int>> B(n);
    for (int i = 0; i < n; i++){
      for (int j = 0; j < 3; j++){
        int p = lower_bound(R2.begin(), R2.end(), T[i][j])- R2.begin();
        if (p != m){
          if (R2[p] == T[i][j]){
            A[i].push_back(p);
          }
        }
      }
      int cnt = R[i].size();
      B[i].resize(cnt);
      for (int j = 0; j < cnt; j++){
        B[i][j] = lower_bound(R2.begin(), R2.end(), R[i][j]) - R2.begin();
      }
    }
    vector<bool> used(m, false);
    for (int i = 0; i < n; i++){
      int cnt = A[i].size();
      for (int j = 0; j < cnt; j++){
        used[A[i][j]] = true;
      }
    }
    vector<int> ecnt(n + m + 2, 0);
    for (int i = 0; i < n; i++){
      ecnt[n + m]++;
      ecnt[i]++;
    }
    for (int i = 0; i < n; i++){
      int cnt = B[i].size();
      for (int j = 0; j < cnt; j++){
        ecnt[i]++;
        ecnt[n + B[i][j]]++;
      }
    }
    for (int i = 0; i < m; i++){
      ecnt[n + i]++;
      ecnt[n + m + 1]++;
    }
    dinic G(n + m + 2, ecnt, n + m, n + m + 1);
    for (int i = 0; i < n; i++){
      G.add_edge(n + m, i);
    }
    for (int i = 0; i < m; i++){
      G.add_edge(n + i, n + m + 1);
    }
    for (int i = 0; i < n; i++){
      int cnt = B[i].size();
      for (int j = 0; j < cnt; j++){
        G.add_edge(i, n + B[i][j]);
      }
    }
    for (int i = 0; i < m; i++){
      if (used[i]){
        G.remove_edge(n + i);
      }
    }
    G.update();
    int F = G.F;
    if (F == n){
      cout << "Valid"<< endl;
    } else if (F < n - 4){
      cout << "Invalid" << endl;
    } else {
      vector<int> ans;
      for (int i = 0; i < n; i++){
        int cnt = A[i].size();
        G.remove_edge(i);
        for (int j = 0; j < cnt; j++){
          G.add_edge(n + A[i][j]);
        }
        G.update();
        if (G.F == n - 1){
          ans.push_back(i);
        }
        G.add_edge(i);
        for (int j = 0; j < cnt; j++){
          G.remove_edge(n + A[i][j]);
        }
      }
      if (ans.empty()){
        cout << "Invalid" << endl;
      } else {
        cout << "Remove" << endl;
        int cnt = ans.size();
        for (int i = 0; i < cnt; i++){
          cout << ans[i] + 1 << endl;
        }
      }
    }
  }
}
accuracy: 1
time_ms: 6580
memory_kb: 6820
final_rank: 11

code_snippet: #include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
#include <set>
#include <iomanip>
#include <numeric>
#include <queue>
#include <string>
#include <map>
#include <fstream>
#include <cassert>
struct Edge {
	int to, pair;
	bool capacity;
};
struct Flow {
	std::vector<std::vector<Edge>> nodes;
	int source, destination;
	std::vector<int> searching, depth;
	std::queue<int> queue;
	bool push(const int current) {
		if (current == destination) {
			return true;
		}
		while (searching[current] < nodes[current].size()) {
			const auto edge = nodes[current][searching[current]];
			if (edge.capacity && depth[current] < depth[edge.to] && push(edge.to)) {
				nodes[current][searching[current]].capacity = false;
				nodes[edge.to][edge.pair].capacity = true;
				return true;
			}
			++searching[current];
		}
		return false;
	}
	void dfs() {
		searching.assign(searching.size(), 0);
		depth.assign(depth.size(), -1);
		depth[source] = 0;
		queue.push(source);
		while (!queue.empty()) {
			const auto top = queue.front(); queue.pop();
			if (top == destination) break;
			for (const auto e : nodes[top]) {
				if (e.capacity && depth[e.to] == -1) {
					depth[e.to] = depth[top] + 1;
					queue.push(e.to);
				}
			}
		}
		while (!queue.empty()) queue.pop();
	}
	int max_flow() {
		int flow{ 0 };
		bool has_flow{ true };
		while (has_flow) {
			has_flow = false;
			dfs();
			while (push(source)) {
				has_flow = true;
				++flow;
			}
		}
		return flow;
	}
	bool remove_match(const int node) {
		if (nodes[node][0].to == source) {
			if (!nodes[node][0].capacity) return false;
			nodes[node][0].capacity = false;
			nodes[source][nodes[node][0].pair].capacity = true;
			for (auto i = 1; i < nodes[node].size(); ++i) {
				if (nodes[node][i].capacity) continue;
				const auto to = nodes[node][i].to;
				nodes[node][i].capacity = true;
				nodes[to][nodes[node][i].pair].capacity = false;
				nodes[to][0].capacity = true;
				nodes[destination][nodes[to][0].pair].capacity = false;
				return true;
			}
			throw 0;
		}
		else {
			throw 0;
		}
	}
	bool add_match(const int node) {
		if (nodes[node][0].capacity) return true;
		if (nodes[node][0].to != source) throw 0;
		searching.assign(searching.size(), 0);
		if (_push_single(node)) {
			nodes[node][0].capacity = true;
			nodes[source][node].capacity = false;
			return true;
		}
		return false;
	}
	int remove_usage(const int node) {
		if (nodes[node][0].to != destination) throw 0;
		if (nodes[node][0].capacity) return -1;
		nodes[node][0].capacity = true;
		nodes[destination][nodes[node][0].pair].capacity = false;
		for (auto i = 1; i < nodes[node].size(); ++i) {
			if (!nodes[node][i].capacity) continue;
			const auto from = nodes[node][i].to;
			nodes[node][i].capacity = false;
			nodes[from][nodes[node][i].pair].capacity = true;
			nodes[from][0].capacity = false;
			nodes[source][nodes[from][0].pair].capacity = true;
			return nodes[node][i].to;
		}
		throw 0;
	}
private:
	bool _push_single(const int current) {
		if (searching[current] != 0) return false;
		searching[current] = 1;
		if (current == destination) return true;
		if (current == source) return false;
		for (auto i = 0; i < nodes[current].size(); ++i) {
			if (!nodes[current][i].capacity || !_push_single(nodes[current][i].to)) continue;
			nodes[current][i].capacity = false;
			nodes[nodes[current][i].to][nodes[current][i].pair].capacity = true;
			return true;
		}
		return false;
	}
};
struct Coordinate {
	int x, y;
	bool operator<(const Coordinate other) const {
		return x == other.x ? y < other.y : x < other.x;
	}
	Coordinate operator-(const Coordinate other) const {
		return Coordinate{ x - other.x, y - other.y };
	}
	Coordinate operator+(const Coordinate other) const {
		return Coordinate{ x + other.x, y + other.y };
	}
};
static std::vector<std::vector<Coordinate>> match{
	{Coordinate{0, 0}, Coordinate{0, -1}, Coordinate{-1, -1}, Coordinate{1, -1}},
	{Coordinate{-1, 0}, Coordinate{0, 0}, Coordinate{1, 0}, Coordinate{0, -1}},
	{Coordinate{0, 0}, Coordinate{1, 0}, Coordinate{2, 0}, Coordinate{3, 0}},
	{Coordinate{-3, 0}, Coordinate{-2, 0}, Coordinate{-1, 0}, Coordinate{0, 0}},
	{Coordinate{0, 0}, Coordinate{1, 0}, Coordinate{1, 1}, Coordinate{2, 1}},
	{Coordinate{0, -1}, Coordinate{0, 0}, Coordinate{1, 0}, Coordinate{1, 1}},
	{Coordinate{0, 0}, Coordinate{-1, 0}, Coordinate{-1, 1}, Coordinate{-2, 1}},
	{Coordinate{0, -1}, Coordinate{0, 0}, Coordinate{-1, 0}, Coordinate{-1, 1}}
};
std::vector<Coordinate> suspect(const std::vector<Coordinate>& coordinate) {
	std::set<Coordinate> set;
	for (const auto& vec : match) {
		for (auto i = 0; i < coordinate.size(); ++i) {
			int j = 0;
			if (std::abs((vec[j].x + vec[j].y) % 2) != std::abs((coordinate[i].x + coordinate[i].y) % 2)) {
				++j;
			}
			const auto diff = coordinate[i] - vec[j];
			std::set<Coordinate> shifted;
			for (const auto& c : vec) {
				shifted.emplace(c + diff);
			}
			for (const auto& c : coordinate) {
				shifted.erase(c);
			}
			if (shifted.size() == 1) {
				set.emplace(*shifted.begin());
			}
		}
	}
	std::vector<Coordinate> result; result.reserve(set.size()); std::copy(set.begin(), set.end(), std::back_inserter(result));
	return result;
}

int main() {
	std::istream& cin = std::cin;
	std::ostream& cout = std::cout;
	cin.sync_with_stdio(false);
	cin.tie(nullptr);
	while (true) {
		int n; cin >> n; if (n == 0) break;
		std::vector<std::vector<Coordinate>> block(n, std::vector<Coordinate>(3));
		for (auto& b : block) {
			for (auto& c : b) cin >> c.x >> c.y;
		}
		std::vector<std::vector<Coordinate>> expand; expand.reserve(n);
		std::map<Coordinate, int> map;
		for (const auto& b : block) {
			expand.push_back(suspect(b));
			for (const auto s : expand.back()) {
				if (map.find(s) == map.end()) {
					map.emplace(s, map.size());
				}
			}
		}
		std::vector<std::vector<Edge>> nodes(n + map.size() + 2);
		const int source = n + map.size();
		const int destination = source + 1;
		const auto add_edge = [&nodes](const int from, const int to) {
			nodes[from].push_back(Edge{ to, (int)nodes[to].size(), true });
			nodes[to].push_back(Edge{ from, (int)nodes[from].size() - 1, false });
		};
		for (auto i = n; i < source; ++i) {
			add_edge(i, destination);
		}
		for (auto i = 0; i < n; ++i) {
			add_edge(source, i);
			for (const auto c : block[i]) {
				const auto f = map.find(c);
				if (f != map.end()) {
					nodes[f->second + n][0].capacity = false;
				}
			}
			for (const auto c : expand[i]) {
				add_edge(i, map.find(c)->second + n);
			}
		}
		Flow flow{ std::move(nodes), source, destination, std::vector<int>(destination + 1), std::vector<int>(destination + 1), std::queue<int>() };
		if (flow.max_flow() == n) {
			cout << "Valid\n";
		}
		else {
			std::queue<int> not_match;
			for (auto i = 0; i < n; ++i) {
				if (flow.nodes[source][i].capacity) not_match.push(i);
			}
			std::vector<int> remove;
			for (auto i = 0; i < n; ++i) {
				flow.remove_match(i);
				flow.nodes[source][i].capacity = false;
				for (const auto c : block[i]) {
					const auto f = map.find(c);
					if (f != map.end()) {
						flow.nodes[f->second + n][0].capacity = true;
					}
				}
				while (!not_match.empty() && (i == not_match.front() || flow.add_match(not_match.front()))) not_match.pop();
				if (not_match.empty()) {
					remove.push_back(i);
				}
				not_match.push(i);
				for (const auto c : block[i]) {
					const auto f = map.find(c);
					if (f != map.end()) {
						const auto removed = flow.remove_usage(f->second + n);
						if (removed >= 0) {
							not_match.push(removed);
						}
						flow.nodes[f->second + n][0].capacity = false;
					}
				}
				flow.nodes[source][i].capacity = true;
			}
			if (remove.empty()) {
				cout << "Invalid\n";
			}
			else {
				cout << "Remove\n";
				for (const auto i : remove) {
					cout << i + 1 << '\n';
				}
			}
		}
	}
}
//https://onlinejudge.u-aizu.ac.jp/challenges/sources/JAG/Prelim/2513?year=2013
accuracy: 1
time_ms: 7380
memory_kb: 6432
final_rank: 15

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define NUM 16
#define SIZE 5005
#define MULT 10

enum Type{
	GU,
	KI,
};

enum Which{
	add_x,
	add_y,
};


struct Data{

	int x[3],y[3];
};

struct LOC{
	LOC(){

		X = Y = 0;
	}

	LOC(int arg_X,int arg_Y){
		X = arg_X;
		Y = arg_Y;
	}
	bool operator<(const struct LOC &arg) const{

		if(X != arg.X){

			return X < arg.X;
		}else{

			return Y < arg.Y;
		}
	}
	bool operator==(const struct LOC &arg) const{

		return X == arg.X && Y == arg.Y;
	}

	int X,Y;
};

struct Info{
	Info(int arg_node_id,int arg_edge_index){
		node_id = arg_node_id;
		edge_index = arg_edge_index;
	}
	int node_id,edge_index;
};


int N;
int table[2][NUM][3][2] = {
						 //GU
						 {{{0,-1},{1,-1},{-1,-1}},
						  {{1,1},{1,0},{2,0}},
						  {{-1,1},{-1,0},{-2,0}},
						  {{1,0},{2,0},{3,0}},
						  {{-2,0},{-1,0},{1,0}},
						  {{-1,0},{1,0},{0,-1}},
						  {{-1,0},{-1,1},{-2,1}},
						  {{1,-1},{0,-1},{-1,0}},
						  {{-1,0},{1,0},{2,0}},
						  {{-3,0},{-2,0},{-1,0}},
						  {{1,0},{1,1},{2,1}},
						  {{1,0},{0,-1},{-1,-1}},
						  {{0,-1},{-1,0},{-1,1}},
						  {{0,-1},{1,-1},{1,-2}},
						  {{0,-1},{1,0},{1,1}},
						  {{0,-1},{-1,-1},{-1,-2}},
						 },
						 //KI
						 {{{0,1},{-1,0},{1,0}},
						  {{1,0},{2,0},{1,-1}},
						  {{-2,0},{-1,0},{-1,-1}},
						  {{-1,1},{0,1},{1,1}},
						  {{-1,0},{1,0},{2,0}},
						  {{-3,0},{-2,0},{-1,0}},
						  {{1,0},{1,-1},{2,-1}},
						  {{-1,1},{0,1},{1,0}},
						  {{1,0},{2,0},{3,0}},
						  {{-2,0},{-1,0},{1,0}},
						  {{-1,0},{0,1},{1,1}},
						  {{-1,0},{-1,-1},{-2,-1}},
						  {{0,1},{-1,1},{-1,2}},
						  {{0,1},{1,0},{1,-1}},
						  {{0,1},{1,1},{1,2}},
						  {{0,1},{-1,0},{-1,-1}},
						 },
						};


map<pair<int,int>,int> FIX,REST;
Data data[SIZE];
bool check[3],deleted[SIZE];
int index_table[SIZE];
LOC work[3];
vector<int> loc[SIZE],REV[MULT*SIZE];
vector<Info> DEL;


int V,E;
vector<int> G[MULT*SIZE]; //グラフの隣接リスト表現
bool used[MULT*SIZE]; //DFSですでに調べたかのフラグ
int match[MULT*SIZE];



void add_edge(int from,int to){
	G[from].push_back(to);
	G[to].push_back(from);
}

//fromからtoへ向かう容量capacityの辺をグラフに追加する
void add_edge2(int from,int to){

	DEL.push_back(Info(from,G[from].size()));
	DEL.push_back(Info(to,G[to].size()));

	G[from].push_back(to);
	G[to].push_back(from); //逆辺の、初期容量は0
}


//増加パスをDFSで探す(node_idのペアを探す)
int dfs(int node_id){
	used[node_id] = true;

	for(int i = 0; i < G[node_id].size(); i++){

		int next = G[node_id][i];

		if(next < N && deleted[next])continue;

		int adj_node_id = G[node_id][i],pair_id = match[adj_node_id];

		if(pair_id != -1 && pair_id < N && deleted[pair_id])continue;

		if((pair_id < 0)|| //隣接するノードに、まだペアが存在しない
				(used[pair_id] == false && dfs(pair_id) == true)){

			match[node_id] = adj_node_id;
			match[adj_node_id] = node_id;
			return true;
		}
	}
	return false;
}


int bipartie_matching(){
	int ret = 0;

	for(int node_id = 0; node_id < V; node_id++){
		if(match[node_id] < 0){ //node_idにペアがいない場合
			for(int i = 0; i < V; i++)used[i] = false;
			if(dfs(node_id)){ //増加パスが存在する場合
				ret++;
			}
		}
	}
	return ret;
}

int bipartie_matching2(int node_id){
	int ret = 0;

	if(match[node_id] < 0){
		for(int i = 0; i < V; i++)used[i] = false;

		if(dfs(node_id)){ //増加パスが存在する場合
			ret++;
		}
	}

	return ret;
}

void func(){

	for(int i = 0; i < MULT*SIZE; i++){

		G[i].clear();
		REV[i].clear();
	}

	FIX.clear();
	REST.clear();

	int num_rest = 0;
	int num_fix = 0;

	for(int i = 0; i < N; i++)loc[i].clear();

	for(int i = 0; i < N; i++){
		for(int k = 0; k < 3; k++){

			scanf("%d %d",&data[i].x[k],&data[i].y[k]);

			FIX[make_pair(data[i].x[k],data[i].y[k])] = num_fix++;
		}
	}

	vector<int> must_remove;

	Type type;
	for(int i = 0; i < N; i++){

		if(abs(data[i].x[0]+data[i].y[0])%2 == 0){

			type = GU;

		}else{

			type = KI;
		}

		for(int k = 0; k < NUM; k++){

			for(int a = 0; a < 3; a++){

				work[a].X = data[i].x[0]+table[type][k][a][add_x];
				work[a].Y = data[i].y[0]+table[type][k][a][add_y];
			}

			for(int a = 0; a < 3; a++){

				check[a] = false;
			}

			for(int base = 1; base <= 2; base++){
				for(int a = 0; a < 3; a++){

					if(work[a].X == data[i].x[base] && work[a].Y == data[i].y[base]){

						check[a] = true; //workの座標は重複しないはず
					}
				}
			}

			int count = 0;
			int rest_index = -1;

			for(int a = 0; a < 3; a++){
				if(check[a]){
					count++;
				}else{

					rest_index = a;
				}
			}

			if(count != 2)continue;

			auto at = FIX.find(make_pair(work[rest_index].X,work[rest_index].Y));

			if(at == FIX.end()){ //指定パネルには引っ掛からない

				auto at2 = REST.find(make_pair(work[rest_index].X,work[rest_index].Y));

				if(at2 != REST.end()){

					int tmp_node = REST[make_pair(work[rest_index].X,work[rest_index].Y)];
					loc[i].push_back(tmp_node);

				}else{ //初出現

					REST[make_pair(work[rest_index].X,work[rest_index].Y)] = N+num_rest;
					loc[i].push_back(N+num_rest);
					num_rest++;
				}

			}else{ //指定パネルに引っかかる場合

				int tmp_node = FIX[make_pair(work[rest_index].X,work[rest_index].Y)];

				loc[i].push_back(-1);//★★条件を示せることを判断するため★★
				REV[tmp_node].push_back(i);
			}
		}

		if(loc[i].size() == 0){

			must_remove.push_back(i); //置くべき場所に置けない→除去必須
			if(must_remove.size() == 2){
				printf("Invalid\n");
				return;
			}
		}else{

			sort(loc[i].begin(),loc[i].end());
			loc[i].erase(unique(loc[i].begin(),loc[i].end()),loc[i].end()); //重複除去
		}
	}

	for(int i = 0; i < num_fix; i++){
		if(REV[i].size() == 0)continue;

		sort(REV[i].begin(),REV[i].end());
		REV[i].erase(unique(REV[i].begin(),REV[i].end()),REV[i].end());
	}

	for(int i = 0; i < N; i++){

		deleted[i] = false;
	}

	V = num_rest+N;

	//ブロックのindex
	for(int i = 0; i < N; i++){

		index_table[i] = i;
	}

	for(int i = 0; i < N; i++){
		for(int k = 0; k < loc[i].size(); k++){
			if(loc[i][k] == -1)continue;
			add_edge(index_table[i],loc[i][k]);
		}
	}

	for(int i = 0; i < V+3; i++)match[i] = -1; //ペアなしにしておく

	int num_match = bipartie_matching();

	if(num_match == N){

		printf("Valid\n");
		return;
	}else if(num_match <= N-5){ //あるセルを除去しても、最大4つ(占めているマスの分)しかマッチングが増えないから
		printf("Invalid\n");
		return;
	}

	vector<int> ANS;

	int L = 0,R = N;
	if(must_remove.size() == 1){

		L = must_remove[0];
		R = L+1;
	}

	int tmp_id;
	vector<int> vec;

	for(int i = L; i < R; i++){

		//まずはブロックiが消えた状態にする
		deleted[i] = true;

		vec.clear();
		DEL.clear();

		//先に全ての辺を張る(ペアの付け替えに使う可能性あり)
		for(int k = 0; k < 3; k++){

			tmp_id = FIX[make_pair(data[i].x[k],data[i].y[k])];
			vec.push_back(V);

			//自分に入次する辺を走査
			for(int a = 0; a < REV[tmp_id].size(); a++){

				add_edge2(REV[tmp_id][a],V);
			}
			V++;
		}

		tmp_id = match[i];

		if(tmp_id != -1){
			match[i] = -1;
			match[tmp_id] = -1;
			num_match--;//ペアを解消したので
			vec.push_back(tmp_id);
		}

		for(int a = 0; a < vec.size(); a++){

			num_match += bipartie_matching2(vec[a]);
		}

		if(num_match == N-1){
			ANS.push_back(i);
		}

		//ブロックiを復活させる
		vec.clear();

		vec.push_back(i);
		deleted[i] = false;

		for(int a = DEL.size()-1; a >= 0; a--){

			G[DEL[a].node_id].erase(G[DEL[a].node_id].begin()+DEL[a].edge_index);
		}

		//ブロックiの指定パネルにmatchしたノードがあるか調べる
		for(int a = 0; a < 3; a++){
			V--;
			tmp_id = match[V];
			if(tmp_id != -1){
				match[V] = -1;
				match[tmp_id] = -1;
				num_match--;
				vec.push_back(tmp_id);
			}
		}

		//全てのノードが揃ったところで再計算
		for(int a = 0; a < vec.size(); a++){

			num_match += bipartie_matching2(vec[a]);
		}
	}

	if(ANS.size() == 0){

		printf("Invalid\n");
	}else{

		printf("Remove\n");
		for(int i = 0; i < ANS.size(); i++){

			printf("%d\n",ANS[i]+1);
		}
	}
}

int main(){

	while(true){

		scanf("%d",&N);
		if(N == 0)break;

		func();
	}

	return 0;
}
accuracy: 1
time_ms: 6370
memory_kb: 8784
final_rank: 12

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define NUM 16
#define SIZE 5005
#define MULT 10

enum Type{
	GU,
	KI,
};

enum Which{
	add_x,
	add_y,
};


struct Data{

	int x[3],y[3];
};

struct LOC{
	LOC(){

		X = Y = 0;
	}

	LOC(int arg_X,int arg_Y){
		X = arg_X;
		Y = arg_Y;
	}
	bool operator<(const struct LOC &arg) const{

		if(X != arg.X){

			return X < arg.X;
		}else{

			return Y < arg.Y;
		}
	}
	bool operator==(const struct LOC &arg) const{

		return X == arg.X && Y == arg.Y;
	}

	int X,Y;
};

struct Info{
	Info(int arg_node_id,int arg_edge_index){
		node_id = arg_node_id;
		edge_index = arg_edge_index;
	}
	int node_id,edge_index;
};


int N;
int table[2][NUM][3][2] = {
						 //GU
						 {{{0,-1},{1,-1},{-1,-1}},
						  {{1,1},{1,0},{2,0}},
						  {{-1,1},{-1,0},{-2,0}},
						  {{1,0},{2,0},{3,0}},
						  {{-2,0},{-1,0},{1,0}},
						  {{-1,0},{1,0},{0,-1}},
						  {{-1,0},{-1,1},{-2,1}},
						  {{1,-1},{0,-1},{-1,0}},
						  {{-1,0},{1,0},{2,0}},
						  {{-3,0},{-2,0},{-1,0}},
						  {{1,0},{1,1},{2,1}},
						  {{1,0},{0,-1},{-1,-1}},
						  {{0,-1},{-1,0},{-1,1}},
						  {{0,-1},{1,-1},{1,-2}},
						  {{0,-1},{1,0},{1,1}},
						  {{0,-1},{-1,-1},{-1,-2}},
						 },
						 //KI
						 {{{0,1},{-1,0},{1,0}},
						  {{1,0},{2,0},{1,-1}},
						  {{-2,0},{-1,0},{-1,-1}},
						  {{-1,1},{0,1},{1,1}},
						  {{-1,0},{1,0},{2,0}},
						  {{-3,0},{-2,0},{-1,0}},
						  {{1,0},{1,-1},{2,-1}},
						  {{-1,1},{0,1},{1,0}},
						  {{1,0},{2,0},{3,0}},
						  {{-2,0},{-1,0},{1,0}},
						  {{-1,0},{0,1},{1,1}},
						  {{-1,0},{-1,-1},{-2,-1}},
						  {{0,1},{-1,1},{-1,2}},
						  {{0,1},{1,0},{1,-1}},
						  {{0,1},{1,1},{1,2}},
						  {{0,1},{-1,0},{-1,-1}},
						 },
						};


map<pair<int,int>,int> FIX,REST;
Data data[SIZE];
bool check[3],deleted[SIZE];
int index_table[SIZE];
LOC work[3];
vector<int> loc[SIZE],REV[MULT*SIZE];
vector<Info> DEL;


int V,E;
vector<int> G[MULT*SIZE]; //グラフの隣接リスト表現
bool used[MULT*SIZE]; //DFSですでに調べたかのフラグ
int match[MULT*SIZE];



void add_edge(int from,int to){
	G[from].push_back(to);
	G[to].push_back(from);
}

//fromからtoへ向かう容量capacityの辺をグラフに追加する
void add_edge2(int from,int to){

	DEL.push_back(Info(from,G[from].size()));
	DEL.push_back(Info(to,G[to].size()));

	G[from].push_back(to);
	G[to].push_back(from); //逆辺の、初期容量は0
}


//増加パスをDFSで探す(node_idのペアを探す)
int dfs(int node_id){
	used[node_id] = true;

	for(int i = 0; i < G[node_id].size(); i++){

		int next = G[node_id][i];

		//printf("ブロックマス e.to:%d cap:%d\n",e.to,e.capacity);
		if(next < N && deleted[next])continue;

		int adj_node_id = G[node_id][i],pair_id = match[adj_node_id];

		if(pair_id != -1 && pair_id < N && deleted[pair_id])continue;

		if((pair_id < 0)|| //隣接するノードに、まだペアが存在しない
				(used[pair_id] == false && dfs(pair_id) == true)){

			match[node_id] = adj_node_id;
			match[adj_node_id] = node_id;
			return true;
		}
	}
	return false;
}


int bipartie_matching(){
	int ret = 0;

	for(int node_id = 0; node_id < V; node_id++){
		if(match[node_id] < 0){ //node_idにペアがいない場合
			for(int i = 0; i < V; i++)used[i] = false;
			if(dfs(node_id)){ //増加パスが存在する場合
				ret++;
			}
		}
	}
	return ret;
}

int bipartie_matching2(int node_id){
	int ret = 0;

	if(match[node_id] < 0){
		for(int i = 0; i < V; i++)used[i] = false;

		if(dfs(node_id)){ //増加パスが存在する場合
			ret++;
		}
	}

	return ret;
}

void func(){

	for(int i = 0; i < MULT*SIZE; i++){

		G[i].clear();
		REV[i].clear();
	}

	FIX.clear();
	REST.clear();

	int num_rest = 0;
	int num_fix = 0;

	for(int i = 0; i < N; i++)loc[i].clear();

	for(int i = 0; i < N; i++){
		for(int k = 0; k < 3; k++){

			scanf("%d %d",&data[i].x[k],&data[i].y[k]);

			FIX[make_pair(data[i].x[k],data[i].y[k])] = num_fix++;
		}
	}

	vector<int> must_remove;

	Type type;
	for(int i = 0; i < N; i++){

		if(abs(data[i].x[0]+data[i].y[0])%2 == 0){

			type = GU;

		}else{

			type = KI;
		}

		for(int k = 0; k < NUM; k++){

			for(int a = 0; a < 3; a++){

				work[a].X = data[i].x[0]+table[type][k][a][add_x];
				work[a].Y = data[i].y[0]+table[type][k][a][add_y];
			}

			for(int a = 0; a < 3; a++){

				check[a] = false;
			}

			for(int base = 1; base <= 2; base++){
				for(int a = 0; a < 3; a++){

					if(work[a].X == data[i].x[base] && work[a].Y == data[i].y[base]){

						check[a] = true; //workの座標は重複しないはず
					}
				}
			}

			int count = 0;
			int rest_index = -1;

			for(int a = 0; a < 3; a++){
				if(check[a]){
					count++;
				}else{

					rest_index = a;
				}
			}

			if(count != 2)continue;

			auto at = FIX.find(make_pair(work[rest_index].X,work[rest_index].Y));

			if(at == FIX.end()){ //指定パネルには引っ掛からない

				auto at2 = REST.find(make_pair(work[rest_index].X,work[rest_index].Y));

				if(at2 != REST.end()){

					int tmp_node = REST[make_pair(work[rest_index].X,work[rest_index].Y)];
					loc[i].push_back(tmp_node);

				}else{ //初出現

					REST[make_pair(work[rest_index].X,work[rest_index].Y)] = N+num_rest;
					loc[i].push_back(N+num_rest);
					num_rest++;
				}

			}else{ //指定パネルに引っかかる場合

				int tmp_node = FIX[make_pair(work[rest_index].X,work[rest_index].Y)];

				loc[i].push_back(-1);//★★条件を示せることを判断するため★★
				REV[tmp_node].push_back(i);
			}
		}

		if(loc[i].size() == 0){

			must_remove.push_back(i); //置くべき場所に置けない→除去必須
			if(must_remove.size() == 2){
				printf("Invalid\n");
				return;
			}
		}else{

			sort(loc[i].begin(),loc[i].end());
			loc[i].erase(unique(loc[i].begin(),loc[i].end()),loc[i].end()); //重複除去
		}
	}

	/*for(int i = 0; i < N; i++){
		printf("\n");
		for(int k = 0; k < loc[i].size(); k++){

			printf("loc[%d][%d]:%d 所属:%d\n",i,k,loc[i][k],ID[loc[i][k]]);
		}
	}

	return ;*/

	for(int i = 0; i < num_fix; i++){
		if(REV[i].size() == 0)continue;

		sort(REV[i].begin(),REV[i].end());
		REV[i].erase(unique(REV[i].begin(),REV[i].end()),REV[i].end());
	}

	for(int i = 0; i < N; i++){

		deleted[i] = false;
	}

	V = num_rest+N;
	//printf("num_rest:%d\n",num_rest);

	//ブロックのindex
	for(int i = 0; i < N; i++){

		index_table[i] = i;
	}

	for(int i = 0; i < N; i++){
		for(int k = 0; k < loc[i].size(); k++){
			if(loc[i][k] == -1)continue;
			add_edge(index_table[i],loc[i][k]);
		}
	}

	for(int i = 0; i < V+3; i++)match[i] = -1; //ペアなしにしておく

	int num_match = bipartie_matching();
	//printf("num_match:%d\n",num_match);

	if(num_match == N){

		printf("Valid\n");
		return;
	}else if(num_match <= N-5){ //あるセルを除去しても、最大4つ(占めているマスの分)しかマッチングが増えないから
		printf("Invalid\n");
		return;
	}

	vector<int> ANS;

	int L = 0,R = N;
	if(must_remove.size() == 1){

		L = must_remove[0];
		R = L+1;
	}

	int tmp_id;
	vector<int> vec;

	for(int i = L; i < R; i++){
	//for(int i = 0; i < N; i++){

		//printf("\ni:%d\n",i);

		//まずはブロックiが消えた状態にする
		deleted[i] = true;

		vec.clear();
		DEL.clear();

		//先に全ての辺を張る(ペアの付け替えに使う可能性あり)
		for(int k = 0; k < 3; k++){

			tmp_id = FIX[make_pair(data[i].x[k],data[i].y[k])];
			vec.push_back(V);

			//自分に入次する辺を走査
			for(int a = 0; a < REV[tmp_id].size(); a++){

				//printf("ブロック%dから%dへ\n",REV[tmp_id][a],V);
				add_edge2(REV[tmp_id][a],V);
			}
			V++;
		}

		tmp_id = match[i];

		if(tmp_id != -1){
			match[i] = -1;
			match[tmp_id] = -1;
			num_match--;//ペアを解消したの
			vec.push_back(tmp_id);
		}

		for(int a = 0; a < vec.size(); a++){

			num_match += bipartie_matching2(vec[a]);
		}

		//printf("num_match:%d\n",num_match);

		if(num_match == N-1){
			//printf("%dはOK\n",i);
			ANS.push_back(i);
		}

		//ブロックiを復活させる
		vec.clear();

		vec.push_back(i);
		deleted[i] = false;

		for(int a = DEL.size()-1; a >= 0; a--){

			G[DEL[a].node_id].erase(G[DEL[a].node_id].begin()+DEL[a].edge_index);
		}

		//ブロックiの指定パネルにmatchしたノードがあるか調べる
		for(int a = 0; a < 3; a++){
			V--;
			tmp_id = match[V];
			if(tmp_id != -1){
				match[V] = -1;
				match[tmp_id] = -1;
				num_match--;
				vec.push_back(tmp_id);
			}
		}

		//全てのノードが揃ったところで再計算
		for(int a = 0; a < vec.size(); a++){

			num_match += bipartie_matching2(vec[a]);
		}
	}

	if(ANS.size() == 0){

		printf("Invalid\n");
	}else{

		printf("Remove\n");
		for(int i = 0; i < ANS.size(); i++){

			printf("%d\n",ANS[i]+1);
		}
	}
}

int main(){

	while(true){

		scanf("%d",&N);
		if(N == 0)break;

		func();
	}

	return 0;
}
accuracy: 1
time_ms: 6480
memory_kb: 8864
final_rank: 14

code_snippet: #include<bits/stdc++.h>
using namespace std;
using Int = long long;
//BEGIN CUT HERE
struct BiMatch{
  int n,time;
  vector<vector<int>> G;
  vector<int> match,used,dead;

  BiMatch(){}
  BiMatch(int n):n(n),time(0),G(n),
                 match(n,-1),used(n,-1),dead(n,0){}

  void add_edge(int u,int v){
    G[u].emplace_back(v);
    G[v].emplace_back(u);
  }

  int dfs(int v){
    used[v]=time;
    for(int u:G[v]){
      if(dead[u]) continue;
      int w=match[u];
      if((w<0)||(used[w]<time&&dfs(w))){
        match[v]=u;
        match[u]=v;
        return 1;
      }
    }
    return 0;
  }

  int build(){
    int res=0;
    for(int v=0;v<n;v++){
      if(dead[v]) continue;
      if(match[v]<0){
        time++;
        res+=dfs(v);
      }
    }
    return res;
  }

  int disable(int v){
    assert(!dead[v]);
    int u=match[v];
    if(~u) match[u]=-1;
    match[v]=-1;
    dead[v]=1;
    time++;
    return ~u?dfs(u)-1:0;
  }

  int enable(int v){
    assert(dead[v]);
    dead[v]=0;
    time++;
    return dfs(v);
  }
};
//END CUT HERE

signed GRL_7_A(){
  int X,Y,E;
  cin>>X>>Y>>E;
  BiMatch bm(X+Y);
  for(int i=0;i<E;i++){
    int x,y;
    cin>>x>>y;
    bm.add_edge(x,X+y);
  }
  cout<<bm.build()<<endl;
  return 0;
}
/*
  verified on 2019/06/16
  http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=GRL_7_A&lang=jp
*/

signed AOJ_2513(){
  cin.tie(0);
  ios::sync_with_stdio(0);

  int n;
  while(cin>>n,n){
    vector<vector<int>> xss;
    vector<vector<int>> yss;
    for(int i=0;i<n;i++){
      vector<int> xs(3),ys(3);
      for(int j=0;j<3;j++) cin>>xs[j]>>ys[j];
      xss.emplace_back(xs);
      yss.emplace_back(ys);
    }

    const int T = 16;
    int dx[T][4]={{ 0,-1, 1, 0},
                  { 0, 1, 1, 2},
                  { 0, 0, 1,-1},
                  { 0,-1,-1,-2},

                  { 0, 1, 2, 3},
                  { 0,-2,-1, 1},

                  {-1, 0, 1, 2},
                  {-3,-2,-1, 0},

                  { 0, 0,-1,-1},
                  { 1, 1, 0, 0},

                  { 0, 0, 1, 1},
                  {-1,-1, 0, 0},

                  {-1, 0, 0, 1},
                  {-2,-1,-1, 0},

                  { 1, 0, 0,-1},
                  { 2, 1, 1, 0},

    };
    int dy[T][4]={{ 0, 0, 0,-1},
                  { 0, 1, 0, 0},
                  { 0,-1,-1,-1},
                  { 0, 0, 1, 0},

                  { 0, 0, 0, 0},
                  { 0, 0, 0, 0},

                  { 0, 0, 0, 0},
                  { 0, 0, 0, 0},

                  { 0,-1,-1,-2},
                  { 1, 0, 0,-1},

                  { 0,-1,-1,-2},
                  { 1, 0, 0,-1},

                  { 0, 0,-1,-1},
                  { 1, 1, 0, 0},

                  { 0, 0,-1,-1},
                  { 1, 1, 0, 0},

    };

    using P = pair<int, int>;

    int m=n;
    map<P, int> mp;
    vector<set<int>> G(n);

    for(int i=0;i<n;i++){
      auto &xs=xss[i];
      auto &ys=yss[i];
      for(int j=0;j<3;j++)
        mp[P(xs[j],ys[j])]=m++;
    }

    vector<set<int> > H(n);
    for(int i=0;i<n;i++){
      auto &xs=xss[i];
      auto &ys=yss[i];
      set<P> tmp;
      for(int j=0;j<3;j++)
        tmp.emplace(xs[j],ys[j]);

      int sy=((xs[0]+ys[0])%2==0?1:-1);

      for(int j=0;j<T;j++){
        set<P> res;
        for(int k=0;k<4;k++)
          res.emplace(xs[0]+dx[j][k],ys[0]+sy*dy[j][k]);

        int cnt=0;
        P uku;
        for(auto p:res){
          if(tmp.count(p)){
            cnt++;
            continue;
          }
          uku=p;
        }
        if(cnt!=3) continue;
        if(!mp.count(uku)) mp[uku]=m++;
        G[i].emplace(mp[uku]);
      }
    }

    BiMatch bm(m);
    for(int i=0;i<n;i++)
      for(int j:G[i])
        bm.add_edge(i,j);

    for(int i=0;i<n;i++){
      auto &xs=xss[i];
      auto &ys=yss[i];
      for(int j=0;j<3;j++)
        bm.disable(mp[P(xs[j],ys[j])]);
    }

    int res=bm.build();

    if(res==n){
      cout<<"Valid"<<"\n";
      continue;
    }

    if(res+4<n){
      cout<<"Invalid"<<"\n";
      continue;
    }

    set<int> ans;
    for(int i=0;i<n;i++){
      auto &xs=xss[i];
      auto &ys=yss[i];
      res+=bm.disable(i);

      for(int j=0;j<3;j++)
        res+=bm.enable(mp[P(xs[j],ys[j])]);

      if(res+1==n) ans.emplace(i);

      for(int j=0;j<3;j++)
        res+=bm.disable(mp[P(xs[j],ys[j])]);

      res+=bm.enable(i);
    }

    if(ans.empty()){
      cout<<"Invalid"<<"\n";
    }else{
      cout<<"Remove"<<"\n";
      for(int i:ans) cout<<i+1<<"\n";
    }
  }
  cout<<flush;
  return 0;
}
/*
  verified on 2019/06/16
  http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2513&lang=jp
*/

signed main(){
  //GRL_7_A();
  AOJ_2513();
  return 0;
}
accuracy: 1
time_ms: 5130
memory_kb: 8016
final_rank: 6

code_snippet: #include<bits/stdc++.h>
using namespace std;
using Int = long long;
using ll = long long;
template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b)a=b;};
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b)a=b;};

struct BiMatch{
  int n,time;
  vector<vector<int>> G;
  vector<int> match,used,dead;

  BiMatch(){}
  BiMatch(int n):n(n),time(0),G(n),
                 match(n,-1),used(n,-1),dead(n,0){}

  void add_edge(int u,int v){
    G[u].emplace_back(v);
    G[v].emplace_back(u);
  }

  int dfs(int v){
    used[v] = time;
    for(int u:G[v]){
      if(dead[u]) continue;
      int w=match[u];
      if((w<0) || (used[w]<time && !dead[w] && dfs(w))){
        match[v]=u;
        match[u]=v;
        return 1;
      }
    }
    return 0;
  }

  int build(){
    int res=0;
    for(int v=0;v<n;v++){
      if(dead[v]) continue;
      if(match[v]<0){
        time++;
        res+=dfs(v);
      }
    }
    return res;
  }

  int disable(int v){
    assert(!dead[v]);
    int u=match[v];
    if(~u) match[u]=-1;
    match[v]=-1;
    dead[v]=1;
    time++;
    return ~u?dfs(u)-1:0;
  }

  int enable(int v){
    assert(dead[v]);
    dead[v]=0;
    time++;
    return dfs(v);
  }
};

signed main(){
  cin.tie(0);
  ios::sync_with_stdio(0);

  int n;
  while(cin>>n,n){
    vector<vector<int>> xss;
    vector<vector<int>> yss;
    for(int i=0;i<n;i++){
      vector<int> xs(3),ys(3);
      for(int j=0;j<3;j++) cin>>xs[j]>>ys[j];
      xss.emplace_back(xs);
      yss.emplace_back(ys);
    }

    const int T = 16;
    int dx[T][4]={{ 0,-1, 1, 0},
                  { 0, 1, 1, 2},
                  { 0, 0, 1,-1},
                  { 0,-1,-1,-2},

                  { 0, 1, 2, 3},
                  { 0,-2,-1, 1},

                  {-1, 0, 1, 2},
                  {-3,-2,-1, 0},

                  { 0, 0,-1,-1},
                  { 1, 1, 0, 0},

                  { 0, 0, 1, 1},
                  {-1,-1, 0, 0},

                  {-1, 0, 0, 1},
                  {-2,-1,-1, 0},

                  { 1, 0, 0,-1},
                  { 2, 1, 1, 0},

    };
    int dy[T][4]={{ 0, 0, 0,-1},
                  { 0, 1, 0, 0},
                  { 0,-1,-1,-1},
                  { 0, 0, 1, 0},

                  { 0, 0, 0, 0},
                  { 0, 0, 0, 0},

                  { 0, 0, 0, 0},
                  { 0, 0, 0, 0},

                  { 0,-1,-1,-2},
                  { 1, 0, 0,-1},

                  { 0,-1,-1,-2},
                  { 1, 0, 0,-1},

                  { 0, 0,-1,-1},
                  { 1, 1, 0, 0},

                  { 0, 0,-1,-1},
                  { 1, 1, 0, 0},

    };

    using P = pair<int, int>;

    int m=n;
    map<P, int> mp;
    vector<set<int>> G(n);

    for(int i=0;i<n;i++){
      auto &xs=xss[i];
      auto &ys=yss[i];
      for(int j=0;j<3;j++)
        mp[P(xs[j],ys[j])]=m++;
    }

    vector<set<int> > H(n);
    for(int i=0;i<n;i++){
      auto &xs=xss[i];
      auto &ys=yss[i];
      set<P> tmp;
      for(int j=0;j<3;j++)
        tmp.emplace(xs[j],ys[j]);

      int sy=((xs[0]+ys[0])%2==0?1:-1);

      for(int j=0;j<T;j++){
        set<P> res;
        for(int k=0;k<4;k++)
          res.emplace(xs[0]+dx[j][k],ys[0]+sy*dy[j][k]);

        int cnt=0;
        P uku;
        for(auto p:res){
          if(tmp.count(p)){
            cnt++;
            continue;
          }
          uku=p;
        }
        if(cnt!=3) continue;
        if(!mp.count(uku)) mp[uku]=m++;
        G[i].emplace(mp[uku]);
      }
    }

    BiMatch bm(m);
    for(int i=0;i<n;i++)
      for(int j:G[i])
        bm.add_edge(i,j);

    for(int i=0;i<n;i++){
      auto &xs=xss[i];
      auto &ys=yss[i];
      for(int j=0;j<3;j++)
        bm.disable(mp[P(xs[j],ys[j])]);
    }

    int res=bm.build();

    if(res==n){
      cout<<"Valid"<<"\n";
      continue;
    }

    if(res+4<n){
      cout<<"Invalid"<<"\n";
      continue;
    }

    set<int> ans;
    for(int i=0;i<n;i++){
      auto &xs=xss[i];
      auto &ys=yss[i];
      res+=bm.disable(i);

      for(int j=0;j<3;j++)
        res+=bm.enable(mp[P(xs[j],ys[j])]);

      if(res+1==n) ans.emplace(i);

      for(int j=0;j<3;j++)
        res+=bm.disable(mp[P(xs[j],ys[j])]);

      res+=bm.enable(i);
    }

    if(ans.empty()){
      cout<<"Invalid"<<"\n";
    }else{
      cout<<"Remove"<<"\n";
      for(int i:ans) cout<<i+1<<"\n";
    }
  }
  cout<<flush;
  return 0;
}
accuracy: 1
time_ms: 5210
memory_kb: 8160
final_rank: 8

code_snippet: #include<bits/stdc++.h>
using namespace std;
using Int = long long;
using ll = long long;
template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b)a=b;};
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b)a=b;};


class BiMatch{
private:
  int L,R,time;
  vector<vector<int>> G;
  vector<int> match,level,used,dead;

  bool bfs(){
    fill(level.begin(),level.end(),-1);
    queue<int> q;
    for(int i=0;i<L;i++){
      if(dead[i]) continue;
      if(match[i]<0){
        level[i]=0;
        q.emplace(i);
      }
    }
    bool found=false;
    while(!q.empty()){
      int v=q.front();q.pop();
      for(int u:G[v]){
        if(dead[u]) continue;
        if(~level[u]) continue;
        level[u]=level[v]+1;
        int w=match[u];
        if(w==-1){
          found=true;
          continue;
        }
        if(~level[w]) continue;
        level[w]=level[u]+1;
        q.emplace(w);
      }
    }
    return found;
  }

  int dfs(int v){
    assert(!dead[v]);
    for(int u:G[v]){
      if(level[v]+1!=level[u]) continue;
      assert(!dead[u]);
      level[u]=-1;
      int w=match[u];
      if(w<0||dfs(w)){
        match[v]=u;
        match[u]=v;
        level[v]=-1;
        return 1;
      }
    }
    level[v]=-1;
    return 0;
  }

  int dfs2(int v){
    used[v]=time;
    for(int u:G[v]){
      if(dead[u]) continue;
      int w=match[u];
      if((w<0) || (used[w]<time && !dead[w] && dfs2(w))){
        match[v]=u;
        match[u]=v;
        return 1;
      }
    }
    return 0;
  }

  int disable(int v){
    assert(!dead[v]);
    int u=match[v];
    if(~u) match[u]=-1;
    match[v]=-1;
    dead[v]=1;
    time++;
    return ~u?dfs2(u)-1:0;
  }

  int enable(int v){
    assert(dead[v]);
    dead[v]=0;
    time++;
    return dfs2(v);
  }

public:
  BiMatch(){}
  BiMatch(int L,int R):L(L),R(R),time(0),G(L+R),
                       match(L+R,-1),level(L+R),used(L+R,-1),dead(L+R,0){}

  void add_edge(int u,int v){
    G[u].emplace_back(v+L);
    G[v+L].emplace_back(u);
  }

  int build(){
    int res=0;
    while(bfs())
      for(int i=0;i<L;i++)
        if(!dead[i]&&match[i]<0&&dfs(i))
          res++;
    return res;
  }
  int disableL(int v){return disable(v);}
  int disableR(int v){return disable(v+L);}
  int enableL(int v){return enable(v);}
  int enableR(int v){return enable(v+L);}
};

//INSERT ABOVE HERE
signed main(){
  cin.tie(0);
  ios::sync_with_stdio(0);

  int n;
  while(cin>>n,n){
    vector<vector<int>> xss;
    vector<vector<int>> yss;
    for(int i=0;i<n;i++){
      vector<int> xs(3),ys(3);
      for(int j=0;j<3;j++) cin>>xs[j]>>ys[j];
      xss.emplace_back(xs);
      yss.emplace_back(ys);
    }

    const int T = 16;
    int dx[T][4]={{ 0,-1, 1, 0},
                  { 0, 1, 1, 2},
                  { 0, 0, 1,-1},
                  { 0,-1,-1,-2},

                  { 0, 1, 2, 3},
                  { 0,-2,-1, 1},

                  {-1, 0, 1, 2},
                  {-3,-2,-1, 0},

                  { 0, 0,-1,-1},
                  { 1, 1, 0, 0},

                  { 0, 0, 1, 1},
                  {-1,-1, 0, 0},

                  {-1, 0, 0, 1},
                  {-2,-1,-1, 0},

                  { 1, 0, 0,-1},
                  { 2, 1, 1, 0},

    };
    int dy[T][4]={{ 0, 0, 0,-1},
                  { 0, 1, 0, 0},
                  { 0,-1,-1,-1},
                  { 0, 0, 1, 0},

                  { 0, 0, 0, 0},
                  { 0, 0, 0, 0},

                  { 0, 0, 0, 0},
                  { 0, 0, 0, 0},

                  { 0,-1,-1,-2},
                  { 1, 0, 0,-1},

                  { 0,-1,-1,-2},
                  { 1, 0, 0,-1},

                  { 0, 0,-1,-1},
                  { 1, 1, 0, 0},

                  { 0, 0,-1,-1},
                  { 1, 1, 0, 0},

    };

    using P = pair<int, int>;

    int m=0;
    map<P, int> mp;
    vector<set<int>> G(n);

    for(int i=0;i<n;i++){
      auto &xs=xss[i];
      auto &ys=yss[i];
      for(int j=0;j<3;j++)
        mp[P(xs[j],ys[j])]=m++;
    }

    vector<set<int> > H(n);
    for(int i=0;i<n;i++){
      auto &xs=xss[i];
      auto &ys=yss[i];
      set<P> tmp;
      for(int j=0;j<3;j++)
        tmp.emplace(xs[j],ys[j]);

      int sy=((xs[0]+ys[0])%2==0?1:-1);

      for(int j=0;j<T;j++){
        set<P> res;
        for(int k=0;k<4;k++)
          res.emplace(xs[0]+dx[j][k],ys[0]+sy*dy[j][k]);

        int cnt=0;
        P uku;
        for(auto p:res){
          if(tmp.count(p)){
            cnt++;
            continue;
          }
          uku=p;
        }
        if(cnt!=3) continue;
        if(!mp.count(uku)) mp[uku]=m++;
        G[i].emplace(mp[uku]);
      }
    }

    BiMatch bm(n,m);
    for(int i=0;i<n;i++)
      for(int j:G[i])
        bm.add_edge(i,j);

    for(int i=0;i<n;i++){
      auto &xs=xss[i];
      auto &ys=yss[i];
      for(int j=0;j<3;j++)
        bm.disableR(mp[P(xs[j],ys[j])]);
    }

    int res=bm.build();
    if(res==n){
      cout<<"Valid"<<"\n";
      continue;
    }

    if(res+4<n){
      cout<<"Invalid"<<"\n";
      continue;
    }

    set<int> ans;
    for(int i=0;i<n;i++){
      auto &xs=xss[i];
      auto &ys=yss[i];
      res+=bm.disableL(i);

      for(int j=0;j<3;j++)
        res+=bm.enableR(mp[P(xs[j],ys[j])]);

      if(res+1==n) ans.emplace(i);

      for(int j=0;j<3;j++)
        res+=bm.disableR(mp[P(xs[j],ys[j])]);

      res+=bm.enableL(i);
    }

    if(ans.empty()){
      cout<<"Invalid"<<"\n";
    }else{
      cout<<"Remove"<<"\n";
      for(int i:ans) cout<<i+1<<"\n";
    }
  }
  cout<<flush;
  return 0;
}
accuracy: 1
time_ms: 5230
memory_kb: 8208
final_rank: 10

code_snippet: #include<bits/stdc++.h>
using namespace std;
using Int = long long;
//BEGIN CUT HERE
struct BiMatch{
  int n,time;
  vector<vector<int>> G;
  vector<int> match,used,dead;

  BiMatch(){}
  BiMatch(int n):n(n),time(0),G(n),
                 match(n,-1),used(n,-1),dead(n,0){}

  void add_edge(int u,int v){
    G[u].emplace_back(v);
    G[v].emplace_back(u);
  }

  int dfs(int v){
    used[v] = time;
    for(int u:G[v]){
      if(dead[u]) continue;
      int w=match[u];
      if((w<0) || (used[w]<time && !dead[w] && dfs(w))){
        match[v]=u;
        match[u]=v;
        return 1;
      }
    }
    return 0;
  }

  int build(){
    int res=0;
    for(int v=0;v<n;v++){
      if(dead[v]) continue;
      if(match[v]<0){
        time++;
        res+=dfs(v);
      }
    }
    return res;
  }

  int disable(int v){
    assert(!dead[v]);
    int u=match[v];
    if(~u) match[u]=-1;
    match[v]=-1;
    dead[v]=1;
    time++;
    return ~u?dfs(u)-1:0;
  }

  int enable(int v){
    assert(dead[v]);
    dead[v]=0;
    time++;
    return dfs(v);
  }
};
//END CUT HERE

signed GRL_7_A(){
  int X,Y,E;
  cin>>X>>Y>>E;
  BiMatch bm(X+Y);
  for(int i=0;i<E;i++){
    int x,y;
    cin>>x>>y;
    bm.add_edge(x,X+y);
  }
  cout<<bm.build()<<endl;
  return 0;
}
/*
  verified on 2019/06/16
  http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=GRL_7_A&lang=jp
*/

signed AOJ_2513(){
  cin.tie(0);
  ios::sync_with_stdio(0);

  int n;
  while(cin>>n,n){
    vector<vector<int>> xss;
    vector<vector<int>> yss;
    for(int i=0;i<n;i++){
      vector<int> xs(3),ys(3);
      for(int j=0;j<3;j++) cin>>xs[j]>>ys[j];
      xss.emplace_back(xs);
      yss.emplace_back(ys);
    }

    const int T = 16;
    int dx[T][4]={{ 0,-1, 1, 0},
                  { 0, 1, 1, 2},
                  { 0, 0, 1,-1},
                  { 0,-1,-1,-2},

                  { 0, 1, 2, 3},
                  { 0,-2,-1, 1},

                  {-1, 0, 1, 2},
                  {-3,-2,-1, 0},

                  { 0, 0,-1,-1},
                  { 1, 1, 0, 0},

                  { 0, 0, 1, 1},
                  {-1,-1, 0, 0},

                  {-1, 0, 0, 1},
                  {-2,-1,-1, 0},

                  { 1, 0, 0,-1},
                  { 2, 1, 1, 0},

    };
    int dy[T][4]={{ 0, 0, 0,-1},
                  { 0, 1, 0, 0},
                  { 0,-1,-1,-1},
                  { 0, 0, 1, 0},

                  { 0, 0, 0, 0},
                  { 0, 0, 0, 0},

                  { 0, 0, 0, 0},
                  { 0, 0, 0, 0},

                  { 0,-1,-1,-2},
                  { 1, 0, 0,-1},

                  { 0,-1,-1,-2},
                  { 1, 0, 0,-1},

                  { 0, 0,-1,-1},
                  { 1, 1, 0, 0},

                  { 0, 0,-1,-1},
                  { 1, 1, 0, 0},

    };

    using P = pair<int, int>;

    int m=n;
    map<P, int> mp;
    vector<set<int>> G(n);

    for(int i=0;i<n;i++){
      auto &xs=xss[i];
      auto &ys=yss[i];
      for(int j=0;j<3;j++)
        mp[P(xs[j],ys[j])]=m++;
    }

    vector<set<int> > H(n);
    for(int i=0;i<n;i++){
      auto &xs=xss[i];
      auto &ys=yss[i];
      set<P> tmp;
      for(int j=0;j<3;j++)
        tmp.emplace(xs[j],ys[j]);

      int sy=((xs[0]+ys[0])%2==0?1:-1);

      for(int j=0;j<T;j++){
        set<P> res;
        for(int k=0;k<4;k++)
          res.emplace(xs[0]+dx[j][k],ys[0]+sy*dy[j][k]);

        int cnt=0;
        P uku;
        for(auto p:res){
          if(tmp.count(p)){
            cnt++;
            continue;
          }
          uku=p;
        }
        if(cnt!=3) continue;
        if(!mp.count(uku)) mp[uku]=m++;
        G[i].emplace(mp[uku]);
      }
    }

    BiMatch bm(m);
    for(int i=0;i<n;i++)
      for(int j:G[i])
        bm.add_edge(i,j);

    for(int i=0;i<n;i++){
      auto &xs=xss[i];
      auto &ys=yss[i];
      for(int j=0;j<3;j++)
        bm.disable(mp[P(xs[j],ys[j])]);
    }

    int res=bm.build();

    if(res==n){
      cout<<"Valid"<<"\n";
      continue;
    }

    if(res+4<n){
      cout<<"Invalid"<<"\n";
      continue;
    }

    set<int> ans;
    for(int i=0;i<n;i++){
      auto &xs=xss[i];
      auto &ys=yss[i];
      res+=bm.disable(i);

      for(int j=0;j<3;j++)
        res+=bm.enable(mp[P(xs[j],ys[j])]);

      if(res+1==n) ans.emplace(i);

      for(int j=0;j<3;j++)
        res+=bm.disable(mp[P(xs[j],ys[j])]);

      res+=bm.enable(i);
    }

    if(ans.empty()){
      cout<<"Invalid"<<"\n";
    }else{
      cout<<"Remove"<<"\n";
      for(int i:ans) cout<<i+1<<"\n";
    }
  }
  cout<<flush;
  return 0;
}
/*
  verified on 2019/06/16
  http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2513&lang=jp
*/

signed main(){
  //GRL_7_A();
  AOJ_2513();
  return 0;
}
accuracy: 1
time_ms: 5230
memory_kb: 8096
final_rank: 7

code_snippet: #include<bits/stdc++.h>
using namespace std;
using Int = long long;
using ll = long long;
template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b)a=b;};
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b)a=b;};

struct BiMatch{
  int n,time;
  vector<vector<int>> G;
  vector<int> match,used,dead;

  BiMatch(){}
  BiMatch(int n):n(n),time(0),G(n),
                 match(n,-1),used(n,-1),dead(n,0){}

  void add_edge(int u,int v){
    G[u].emplace_back(v);
    G[v].emplace_back(u);
  }

  int dfs(int v){
    used[v] = time;
    for(int u:G[v]){
      if(dead[u]) continue;
      int w=match[u];
      if((w<0) || (used[w]<time && !dead[w] && dfs(w))){
        match[v]=u;
        match[u]=v;
        return 1;
      }
    }
    return 0;
  }

  int build(){
    int res=0;
    for(int v=0;v<n;v++){
      if(dead[v]) continue;
      if(match[v]<0){
        time++;
        res+=dfs(v);
      }
    }
    return res;
  }

  int disable(int v){
    int u=match[v];
    if(~u) match[u]=-1;
    match[v]=-1;
    dead[v]=1;
    time++;
    return ~u?dfs(u)-1:0;
  }

  int enable(int v){
    assert(dead[v]);
    dead[v]=0;
    time++;
    return dfs(v);
  }
};

signed main(){
  cin.tie(0);
  ios::sync_with_stdio(0);

  int n;
  while(cin>>n,n){
    vector<vector<int>> xss;
    vector<vector<int>> yss;
    for(int i=0;i<n;i++){
      vector<int> xs(3),ys(3);
      for(int j=0;j<3;j++) cin>>xs[j]>>ys[j];
      xss.emplace_back(xs);
      yss.emplace_back(ys);
    }

    const int T = 16;
    int dx[T][4]={{ 0,-1, 1, 0},
                  { 0, 1, 1, 2},
                  { 0, 0, 1,-1},
                  { 0,-1,-1,-2},

                  { 0, 1, 2, 3},
                  { 0,-2,-1, 1},

                  {-1, 0, 1, 2},
                  {-3,-2,-1, 0},

                  { 0, 0,-1,-1},
                  { 1, 1, 0, 0},

                  { 0, 0, 1, 1},
                  {-1,-1, 0, 0},

                  {-1, 0, 0, 1},
                  {-2,-1,-1, 0},

                  { 1, 0, 0,-1},
                  { 2, 1, 1, 0},

    };
    int dy[T][4]={{ 0, 0, 0,-1},
                  { 0, 1, 0, 0},
                  { 0,-1,-1,-1},
                  { 0, 0, 1, 0},

                  { 0, 0, 0, 0},
                  { 0, 0, 0, 0},

                  { 0, 0, 0, 0},
                  { 0, 0, 0, 0},

                  { 0,-1,-1,-2},
                  { 1, 0, 0,-1},

                  { 0,-1,-1,-2},
                  { 1, 0, 0,-1},

                  { 0, 0,-1,-1},
                  { 1, 1, 0, 0},

                  { 0, 0,-1,-1},
                  { 1, 1, 0, 0},

    };

    using P = pair<int, int>;

    int m=n;
    map<P, int> mp;
    vector<set<int>> G(n);

    for(int i=0;i<n;i++){
      auto &xs=xss[i];
      auto &ys=yss[i];
      for(int j=0;j<3;j++)
        mp[P(xs[j],ys[j])]=m++;
    }

    vector<set<int> > H(n);
    for(int i=0;i<n;i++){
      auto &xs=xss[i];
      auto &ys=yss[i];
      set<P> tmp;
      for(int j=0;j<3;j++)
        tmp.emplace(xs[j],ys[j]);

      int sy=((xs[0]+ys[0])%2==0?1:-1);

      for(int j=0;j<T;j++){
        set<P> res;
        for(int k=0;k<4;k++)
          res.emplace(xs[0]+dx[j][k],ys[0]+sy*dy[j][k]);

        int cnt=0;
        P uku;
        for(auto p:res){
          if(tmp.count(p)){
            cnt++;
            continue;
          }
          uku=p;
        }
        if(cnt!=3) continue;
        if(!mp.count(uku)) mp[uku]=m++;
        G[i].emplace(mp[uku]);
      }
    }

    BiMatch bm(m);
    for(int i=0;i<n;i++)
      for(int j:G[i])
        bm.add_edge(i,j);

    for(int i=0;i<n;i++){
      auto &xs=xss[i];
      auto &ys=yss[i];
      for(int j=0;j<3;j++)
        bm.disable(mp[P(xs[j],ys[j])]);
    }

    int res=bm.build();

    if(res==n){
      cout<<"Valid"<<"\n";
      continue;
    }

    if(res+4<n){
      cout<<"Invalid"<<"\n";
      continue;
    }

    set<int> ans;
    for(int i=0;i<n;i++){
      auto &xs=xss[i];
      auto &ys=yss[i];
      res+=bm.disable(i);

      for(int j=0;j<3;j++)
        res+=bm.enable(mp[P(xs[j],ys[j])]);

      if(res+1==n) ans.emplace(i);

      for(int j=0;j<3;j++)
        res+=bm.disable(mp[P(xs[j],ys[j])]);

      res+=bm.enable(i);
    }

    if(ans.empty()){
      cout<<"Invalid"<<"\n";
    }else{
      cout<<"Remove"<<"\n";
      for(int i:ans) cout<<i+1<<"\n";
    }
  }
  cout<<flush;
  return 0;
}
accuracy: 1
time_ms: 5230
memory_kb: 8160
final_rank: 9

code_snippet: #include<bits/stdc++.h>
using namespace std;
using Int = long long;
using ll = long long;
template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b)a=b;};
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b)a=b;};

struct BiMatch{
  Int n,time;
  vector<vector<Int>> G;
  vector<Int> match, used, dead;

  BiMatch(){}
  BiMatch(Int n):n(n), time(0), G(n), match(n, -1), used(n,-1), dead(n, 0){}

  void add_edge(Int u, Int v){
    G[u].emplace_back(v);
    G[v].emplace_back(u);
  }

  bool dfs(Int v){
    assert(!dead[v]);
    used[v] = time;
    for(Int i=0;i<(Int)G[v].size();i++){
      Int u = G[v][i], w = match[u];
      if(dead[u]) continue;
      if(w < 0 || (used[w]<time && !dead[w] && dfs(w))){
        match[v] = u;
        match[u] = v;
        return true;
      }
    }
    return false;
  }

  Int build(){
    Int res = 0;
    for(Int v=0;v<n;v++){
      if(dead[v]) continue;
      if(match[v] < 0){
        time++;
        res+=dfs(v);
      }
    }
    return res;
  }

  Int disable(Int v){
    Int u=match[v];
    if(~u) match[u]=-1;
    match[v]=-1;
    dead[v]=1;
    time++;
    return ~u?dfs(u)-1:0;
  }

  Int enable(Int v){
    assert(dead[v]);
    dead[v]=0;
    time++;
    return dfs(v);
  }
};

signed main(){
  cin.tie(0);
  ios::sync_with_stdio(0);

  Int n;
  while(cin>>n,n){
    vector<vector<Int>> xss;
    vector<vector<Int>> yss;
    for(Int i=0;i<n;i++){
      vector<Int> xs(3),ys(3);
      for(Int j=0;j<3;j++) cin>>xs[j]>>ys[j];
      xss.emplace_back(xs);
      yss.emplace_back(ys);
    }

    const Int T = 16;
    Int dx[T][4]={{ 0,-1, 1, 0},
                  { 0, 1, 1, 2},
                  { 0, 0, 1,-1},
                  { 0,-1,-1,-2},

                  { 0, 1, 2, 3},
                  { 0,-2,-1, 1},

                  {-1, 0, 1, 2},
                  {-3,-2,-1, 0},

                  { 0, 0,-1,-1},
                  { 1, 1, 0, 0},

                  { 0, 0, 1, 1},
                  {-1,-1, 0, 0},

                  {-1, 0, 0, 1},
                  {-2,-1,-1, 0},

                  { 1, 0, 0,-1},
                  { 2, 1, 1, 0},

    };
    Int dy[T][4]={{ 0, 0, 0,-1},
                  { 0, 1, 0, 0},
                  { 0,-1,-1,-1},
                  { 0, 0, 1, 0},

                  { 0, 0, 0, 0},
                  { 0, 0, 0, 0},

                  { 0, 0, 0, 0},
                  { 0, 0, 0, 0},

                  { 0,-1,-1,-2},
                  { 1, 0, 0,-1},

                  { 0,-1,-1,-2},
                  { 1, 0, 0,-1},

                  { 0, 0,-1,-1},
                  { 1, 1, 0, 0},

                  { 0, 0,-1,-1},
                  { 1, 1, 0, 0},

    };

    using P = pair<Int, Int>;

    Int m=n;
    map<P, Int> mp;
    vector<set<Int> > G(n);

    for(Int i=0;i<n;i++){
      auto &xs=xss[i];
      auto &ys=yss[i];
      for(Int j=0;j<3;j++)
        mp[P(xs[j],ys[j])]=m++;
    }

    vector<set<Int> > H(n);
    for(Int i=0;i<n;i++){
      auto &xs=xss[i];
      auto &ys=yss[i];
      set<P> tmp;
      for(Int j=0;j<3;j++)
        tmp.emplace(xs[j],ys[j]);

      Int sy=((xs[0]+ys[0])%2==0?1:-1);

      for(Int j=0;j<T;j++){
        set<P> res;
        for(Int k=0;k<4;k++)
          res.emplace(xs[0]+dx[j][k],ys[0]+sy*dy[j][k]);

        Int cnt=0;
        P uku;
        for(auto p:res){
          if(tmp.count(p)){
            cnt++;
            continue;
          }
          uku=p;
        }
        if(cnt!=3) continue;
        if(!mp.count(uku)) mp[uku]=m++;
        G[i].emplace(mp[uku]);
      }
    }

    BiMatch bm(m);
    for(Int i=0;i<n;i++)
      for(Int j:G[i])
        bm.add_edge(i,j);

    for(Int i=0;i<n;i++){
      auto &xs=xss[i];
      auto &ys=yss[i];
      for(Int j=0;j<3;j++)
        bm.disable(mp[P(xs[j],ys[j])]);
    }

    Int res=bm.build();

    if(res==n){
      cout<<"Valid"<<"\n";
      continue;
    }

    if(res+4<n){
      cout<<"Invalid"<<"\n";
      continue;
    }

    set<Int> ans;
    for(Int i=0;i<n;i++){
      auto &xs=xss[i];
      auto &ys=yss[i];
      res+=bm.disable(i);

      for(Int j=0;j<3;j++)
        res+=bm.enable(mp[P(xs[j],ys[j])]);

      if(res+1==n) ans.emplace(i);

      for(Int j=0;j<3;j++)
        res+=bm.disable(mp[P(xs[j],ys[j])]);

      res+=bm.enable(i);
    }

    if(ans.empty()){
      cout<<"Invalid"<<"\n";
    }else{
      cout<<"Remove"<<"\n";
      for(Int i:ans) cout<<i+1<<"\n";
    }
  }
  cout<<flush;
  return 0;
}
accuracy: 1
time_ms: 6530
memory_kb: 8436
final_rank: 13

code_snippet: #include<bits/stdc++.h>
using namespace std;
using Int = long long;
using ll = long long;
template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b)a=b;};
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b)a=b;};

struct BiMatch{
  Int n;
  vector<vector<Int> > G;
  vector<Int> match, used, dead;

  BiMatch(){}
  BiMatch(Int sz):n(sz), G(sz), match(sz), used(sz), dead(sz, 0){}

  void add_edge(Int u, Int v){
    G[u].emplace_back(v);
    G[v].emplace_back(u);
  }

  bool dfs(Int v){
    assert(!dead[v]);
    used[v] = true;
    for(Int i=0;i<(Int)G[v].size();i++){
      Int u = G[v][i], w = match[u];
      if(dead[u]) continue;
      if(w < 0 || (!used[w] && !dead[w] && dfs(w))){
        match[v] = u;
        match[u] = v;
        return true;
      }
    }
    return false;
  }

  Int build(){
    Int res = 0;
    fill(match.begin(), match.end(), -1);

    fill(used.begin(), used.end(), 0);
    for(Int v=0;v<n;v++){
      if(!dead[v] && match[v] < 0){
        if(dfs(v)){
          res++;
          fill(used.begin(), used.end(), 0);
        }
      }
    }
    return res;
  }

  Int check(Int v){
    assert(!dead[v] && match[v]<0);
    int res=dfs(v);
    if(res) fill(used.begin(), used.end(), 0);
    return res;
  }

  Int disable(Int v){
    Int res=match[v];
    if(~match[v]) match[match[v]]=-1;
    match[v]=-1;
    dead[v]=1;
    return res;
  }

  Int enable(Int v){
    assert(dead[v]);
    dead[v]=0;
    return check(v);
  }
};

signed main(){
  cin.tie(0);
  ios::sync_with_stdio(0);

  Int n;
  while(cin>>n,n){
    vector<vector<Int>> xss;
    vector<vector<Int>> yss;
    for(Int i=0;i<n;i++){
      vector<Int> xs(3),ys(3);
      for(Int j=0;j<3;j++) cin>>xs[j]>>ys[j];
      xss.emplace_back(xs);
      yss.emplace_back(ys);
    }

    const Int T = 16;
    Int dx[T][4]={{ 0,-1, 1, 0},
                  { 0, 1, 1, 2},
                  { 0, 0, 1,-1},
                  { 0,-1,-1,-2},

                  { 0, 1, 2, 3},
                  { 0,-2,-1, 1},

                  {-1, 0, 1, 2},
                  {-3,-2,-1, 0},

                  { 0, 0,-1,-1},
                  { 1, 1, 0, 0},

                  { 0, 0, 1, 1},
                  {-1,-1, 0, 0},

                  {-1, 0, 0, 1},
                  {-2,-1,-1, 0},

                  { 1, 0, 0,-1},
                  { 2, 1, 1, 0},

    };
    Int dy[T][4]={{ 0, 0, 0,-1},
                  { 0, 1, 0, 0},
                  { 0,-1,-1,-1},
                  { 0, 0, 1, 0},

                  { 0, 0, 0, 0},
                  { 0, 0, 0, 0},

                  { 0, 0, 0, 0},
                  { 0, 0, 0, 0},

                  { 0,-1,-1,-2},
                  { 1, 0, 0,-1},

                  { 0,-1,-1,-2},
                  { 1, 0, 0,-1},

                  { 0, 0,-1,-1},
                  { 1, 1, 0, 0},

                  { 0, 0,-1,-1},
                  { 1, 1, 0, 0},

    };

    using P = pair<Int, Int>;

    Int m=n;
    map<P, Int> mp;
    vector<set<Int> > G(n);

    for(Int i=0;i<n;i++){
      auto &xs=xss[i];
      auto &ys=yss[i];
      for(Int j=0;j<3;j++)
        mp[P(xs[j],ys[j])]=m++;
    }

    vector<set<Int> > H(n);
    for(Int i=0;i<n;i++){
      auto &xs=xss[i];
      auto &ys=yss[i];
      set<P> tmp;
      for(Int j=0;j<3;j++)
        tmp.emplace(xs[j],ys[j]);

      Int sy=((xs[0]+ys[0])%2==0?1:-1);

      for(Int j=0;j<T;j++){
        set<P> res;
        for(Int k=0;k<4;k++)
          res.emplace(xs[0]+dx[j][k],ys[0]+sy*dy[j][k]);

        Int cnt=0;
        P uku;
        for(auto p:res){
          if(tmp.count(p)){
            cnt++;
            continue;
          }
          uku=p;
        }
        if(cnt!=3) continue;
        if(!mp.count(uku)) mp[uku]=m++;
        G[i].emplace(mp[uku]);
        //cout<<i<<":"<<uku.first<<" "<<uku.second<<endl;
      }
    }

    BiMatch bm(m);
    for(Int i=0;i<n;i++)
      for(Int j:G[i])
        bm.add_edge(i,j);

    for(Int i=0;i<n;i++){
      auto &xs=xss[i];
      auto &ys=yss[i];
      for(Int j=0;j<3;j++)
        bm.disable(mp[P(xs[j],ys[j])]);
    }

    Int res=bm.build();
    //cout<<res<<" "<<n<<endl;

    if(res==n){
      cout<<"Valid"<<"\n";
      continue;
    }

    if(res+4<n){
      cout<<"Invalid"<<"\n";
      continue;
    }

    set<Int> ans;
    for(Int i=0;i<n;i++){
      auto &xs=xss[i];
      auto &ys=yss[i];
      Int u=bm.disable(i);
      if(~u){
        res--;
        res+=bm.check(u);
      }
      for(Int j=0;j<3;j++)
        res+=bm.enable(mp[P(xs[j],ys[j])]);

      if(res+1==n) ans.emplace(i);

      for(Int j=0;j<3;j++){
        Int k=bm.disable(mp[P(xs[j],ys[j])]);
        if(~k){
          res--;
          res+=bm.check(k);
        }
      }
      res+=bm.enable(i);
    }

    if(ans.empty()){
      cout<<"Invalid"<<"\n";
    }else{
      cout<<"Remove"<<"\n";
      for(Int i:ans) cout<<i+1<<"\n";
    }
  }
  cout<<flush;
  return 0;
}
accuracy: 1
time_ms: 7400
memory_kb: 8476
final_rank: 16

code_snippet: #include <bits/stdc++.h>
using namespace std;

#define for_(i,a,b) for(int i=(a);i<(b);++i)
#define allof(a) (a).begin(),(a).end()
typedef pair< int, int > pii;

class BipartiteMatching {
private:
	int V;
	vector< vector< int > > adj;
	vector< int > match;
	vector< bool > used;
	vector< bool > visible;
	
	bool dfs(int v) {
		used[v] = 1;
		
		for (int u : adj[v]) {
			if (!visible[u]) continue;
			
			int w = match[u];
			if (w < 0 || (!used[w] && dfs(w))) {
				match[v] = u;
				match[u] = v;
				return 1;
			}
		}
		
		return 0;
	}
	
public:
	BipartiteMatching(int n) : V(n), adj(n, vector< int >()), match(n, -1), used(n, 0), visible(n, false) {}
	
	void addEdge(int u, int v) {
		adj[u].push_back(v);
		adj[v].push_back(u);
	}
	
	bool startDFS(int v) {
		if (!visible[v] || match[v] >= 0) return false;
		fill(allof(used), 0);
		return dfs(v);
	}
	
	void setVisible(int v) { visible[v] = true; }
	void setUnvisible(int v) { visible[v] = false; }
	void setUnmatch(int v) { match[v] = -1; }
	
	int getMatch(int v) { return match[v]; }
};



int n, x[5000][3], y[5000][3], par[5000][3];
set< pii > candidates[5000];
set< int > cand_id[5000];

const int dx[2][3] = {{1,0,-1}, {1,0,-1}};
const int dy[2][3] = {{0,-1,0}, {0,1,0}};
const int add[3][2][3] = {
	{{0,0,0}, {0,0,0}},
	{{1,0,1}, {0,1,0}},
	{{0,1,0}, {1,0,1}}
};

int getPar(pii p) { return (abs(p.first) + abs(p.second)) % 2; }

bool validPieces(set< pii >& pset) {
	int deg_sum = 0, max_deg = 0;
	for (pii p : pset) {
		int deg = 0;
		for_(d,0,3) {
			pii pi(p.first + dx[getPar(p)][d], p.second + dy[getPar(p)][d]);
			deg += pset.count(pi);
		}
		max_deg = max(max_deg, deg);
		deg_sum += deg;
	}
	
	if (deg_sum != 6) return false;
	if (max_deg == 3) return true;
	
	for (pii p : pset) for_(a,0,3) {
		bool flag = true;
		pii cur = p;
		int par = getPar(p);
		for_(d,0,3) {
			pii np(cur.first + dx[getPar(cur)][add[a][par][d]], cur.second + dy[getPar(cur)][add[a][par][d]]);
			flag &= (pset.count(np) == 1);
			cur = np;
		}
		if (flag) return true;
	}
	return false;
}

void makeCandidates() {
	for_(i,0,n) {
		candidates[i].clear();
		set< pii > pset;
		for_(j,0,3) pset.insert(pii(x[i][j], y[i][j]));
		for_(j,0,3) for_(d,0,3) {
			set< pii > pset_j = pset;
			pii np(x[i][j] + dx[par[i][j]][d], y[i][j] + dy[par[i][j]][d]);
			pset_j.insert(np);
			if (pset_j.size() == 4 && validPieces(pset_j)) candidates[i].insert(np);
		}
	}
}

void solve() {
	makeCandidates();
	
	map< pii, int > pii_to_id;
	int new_id = 0;
	for_(i,0,n) {
		for (pii p : candidates[i]) {
			if (pii_to_id.count(p)) continue;
			pii_to_id[p] = new_id++;
			cand_id[i].insert(pii_to_id[p]);
		}
	}
	
	int m = pii_to_id.size();
	BipartiteMatching bm(n + m);
	for_(i,0,n) for (pii p : candidates[i]) bm.addEdge(i, n + pii_to_id[p]);
		
	for_(i,0,n+m) bm.setVisible(i);
	for_(i,0,n) for_(j,0,3) {
		pii p(x[i][j], y[i][j]);
		if (pii_to_id.count(p)) bm.setUnvisible(n + pii_to_id[p]);
	}
	
	vector< int > miss;
	for_(v,0,n) bm.startDFS(v);
	for_(v,0,n) if (bm.getMatch(v) < 0) miss.push_back(v);
	
	if (miss.size() == 0) puts("Valid");
	else if (miss.size() > 4) puts("Invalid");
	else {
		vector< int > ans;		
		for_(u,0,n) {
			for_(j,0,3) {
				pii p(x[u][j], y[u][j]);
				if (pii_to_id.count(p)) bm.setVisible(n + pii_to_id[p]);
			}
			int id = bm.getMatch(u);
			if (id >= 0) {
				bm.setUnmatch(u);
				bm.setUnmatch(id);
			}
			
			for_(v,0,n) if (v != u) bm.startDFS(v);
			bool no_miss = true;
			for_(v,0,n) if (v != u) no_miss &= (bm.getMatch(v) >= 0);
			if (no_miss) ans.push_back(u);
			
			vector< int > match_v(m, -1);
			for_(v,0,n) {
				int id = bm.getMatch(v);
				if (id >= 0) match_v[id - n] = v;
			}
			
			for_(j,0,3) {
				pii p(x[u][j], y[u][j]);
				if (pii_to_id.count(p)) {
					id = n + pii_to_id[p];
					bm.setUnvisible(id);
					if (match_v[id - n] >= 0) {
						bm.setUnmatch(match_v[id - n]);
						bm.setUnmatch(id);
					}
				}
			}
		}
		
		if (ans.size() == 0) puts("Invalid");
		else {
			puts("Remove");
			for (int v : ans) printf("%d\n", v+1);
		}
	}
}

int main() {
	while (1) {
		cin >> n;
		if (n == 0) break;
		for_(i,0,n) for_(j,0,3) {
			cin >> x[i][j] >> y[i][j];
			par[i][j] = (abs(x[i][j]) + abs(y[i][j])) % 2;
		}
		solve();
	}
}
accuracy: 1
time_ms: 6270
memory_kb: 13720
final_rank: 18

code_snippet: #include <bits/stdc++.h>
using namespace std;

#define for_(i,a,b) for(int i=(a);i<(b);++i)
#define allof(a) (a).begin(),(a).end()
typedef pair< int, int > pii;

class BipartiteMatching {
private:
	int V;
	vector< vector< int > > adj;
	vector< int > match;
	vector< bool > used;
	vector< bool > visible;
	
	bool dfs(int v) {
		used[v] = 1;
		
		for (int u : adj[v]) {
			if (!visible[u]) continue;
			
			int w = match[u];
			if (w < 0 || (!used[w] && dfs(w))) {
				match[v] = u;
				match[u] = v;
				return 1;
			}
		}
		
		return 0;
	}
	
public:
	BipartiteMatching(int n) : V(n), adj(n, vector< int >()), match(n, -1), used(n, 0), visible(n, false) {}
	
	void addEdge(int u, int v) {
		adj[u].push_back(v);
		adj[v].push_back(u);
	}
	
	bool startDFS(int v) {
		if (!visible[v] || match[v] >= 0) return false;
		fill(allof(used), 0);
		return dfs(v);
	}
	
	void setVisible(int v) { visible[v] = true; }
	void setUnvisible(int v) { visible[v] = false; }
	void setUnmatch(int v) { match[v] = -1; }
	
	int getMatch(int v) { return match[v]; }
};



int n, x[5000][3], y[5000][3], par[5000][3];
set< pii > candidates[5000];
set< int > cand_id[5000];

const int dx[2][3] = {{1,0,-1}, {1,0,-1}};
const int dy[2][3] = {{0,-1,0}, {0,1,0}};
const int add[3][2][3] = {
	{{0,0,0}, {0,0,0}},
	{{1,0,1}, {0,1,0}},
	{{0,1,0}, {1,0,1}}
};

int getPar(pii p) { return (abs(p.first) + abs(p.second)) % 2; }

bool validPieces(set< pii >& pset) {
	int deg_sum = 0, max_deg = 0;
	for (pii p : pset) {
		int deg = 0;
		for_(d,0,3) {
			pii pi(p.first + dx[getPar(p)][d], p.second + dy[getPar(p)][d]);
			deg += pset.count(pi);
		}
		max_deg = max(max_deg, deg);
		deg_sum += deg;
	}
	
	if (deg_sum != 6) return false;
	if (max_deg == 3) return true;
	
	for (pii p : pset) for_(a,0,3) {
		bool flag = true;
		pii cur = p;
		int par = getPar(p);
		for_(d,0,3) {
			pii np(cur.first + dx[getPar(cur)][add[a][par][d]], cur.second + dy[getPar(cur)][add[a][par][d]]);
			flag &= (pset.count(np) == 1);
			cur = np;
		}
		if (flag) return true;
	}
	return false;
}

void makeCandidates() {
	for_(i,0,n) {
		candidates[i].clear();
		set< pii > pset;
		for_(j,0,3) pset.insert(pii(x[i][j], y[i][j]));
		for_(j,0,3) for_(d,0,3) {
			set< pii > pset_j = pset;
			pii np(x[i][j] + dx[par[i][j]][d], y[i][j] + dy[par[i][j]][d]);
			pset_j.insert(np);
			if (pset_j.size() == 4 && validPieces(pset_j)) candidates[i].insert(np);
		}
	}
}

void solve() {
	makeCandidates();
	
	map< pii, int > pii_to_id;
	int new_id = 0;
	for_(i,0,n) {
		for (pii p : candidates[i]) {
			if (pii_to_id.count(p)) continue;
			pii_to_id[p] = new_id++;
			cand_id[i].insert(pii_to_id[p]);
		}
	}
	
	int m = pii_to_id.size();
	BipartiteMatching bm(n + m);
	for_(i,0,n) for (pii p : candidates[i]) bm.addEdge(i, n + pii_to_id[p]);
		
	for_(i,0,n+m) bm.setVisible(i);
	for_(i,0,n) for_(j,0,3) {
		pii p(x[i][j], y[i][j]);
		if (pii_to_id.count(p)) bm.setUnvisible(n + pii_to_id[p]);
	}
	
	vector< int > miss;
	for_(v,0,n) bm.startDFS(v);
	for_(v,0,n) if (bm.getMatch(v) < 0) miss.push_back(v);
	
	if (miss.size() == 0) puts("Valid");
	else if (miss.size() > 4) puts("Invalid");
	else {
		vector< int > ans;		
		for_(u,0,n) {
			for_(j,0,3) {
				pii p(x[u][j], y[u][j]);
				if (pii_to_id.count(p)) bm.setVisible(n + pii_to_id[p]);
			}
			int id = bm.getMatch(u);
			if (id >= 0) {
				bm.setUnmatch(u);
				bm.setUnmatch(id);
			}
			
			for_(v,0,n) if (v != u) bm.startDFS(v);
			bool no_miss = true;
			for_(v,0,n) if (v != u) no_miss &= (bm.getMatch(v) >= 0);
			if (no_miss) ans.push_back(u);
			
			for_(j,0,3) {
				pii p(x[u][j], y[u][j]);
				if (pii_to_id.count(p)) {
					id = n + pii_to_id[p];
					bm.setUnvisible(id);
					for_(v,0,n) {
						if (bm.getMatch(v) == id) {
							bm.setUnmatch(v);
							bm.setUnmatch(id);
						}
					}
				}
			}
		}
		
		if (ans.size() == 0) puts("Invalid");
		else {
			puts("Remove");
			for (int v : ans) printf("%d\n", v+1);
		}
	}
}

int main() {
	while (1) {
		cin >> n;
		if (n == 0) break;
		for_(i,0,n) for_(j,0,3) {
			cin >> x[i][j] >> y[i][j];
			par[i][j] = (abs(x[i][j]) + abs(y[i][j])) % 2;
		}
		solve();
	}
}
accuracy: 1
time_ms: 6120
memory_kb: 13792
final_rank: 17

code_snippet: #include <bits/stdc++.h>

using namespace std;

struct Bipartite_Matching
{
  vector< vector< int > > graph;
  vector< int > match, alive, used;
  int timestamp = 0;

  Bipartite_Matching(int n)
  {
    graph.resize(n);
    alive.assign(n, 1);
    used.assign(n, 0);
    match.assign(n, -1);
  }

  void add_edge(int u, int v)
  {
    graph[u].push_back(v);
    graph[v].push_back(u);
  }

  bool dfs(int v)
  {
    used[v] = timestamp;
    for(int i = 0; i < graph[v].size(); i++) {
      int u = graph[v][i], w = match[u];
      if(alive[u] == 0) continue;
      if(w == -1 || (used[w] != timestamp && dfs(w))) {
        match[v] = u;
        match[u] = v;
        return (true);
      }
    }
    return (false);
  }

  int bipartite_matching()
  {
    int ret = 0;
    for(int i = 0; i < graph.size(); i++) {
      if(alive[i] == 0) continue;
      if(match[i] == -1) {
        ++timestamp;
        ret += dfs(i);
      }
    }
    return (ret);
  }

  int add(int k)
  {
    alive[k] = 1;
    ++timestamp;
    return (dfs(k));
  }

  int kill(int k)
  {
    alive[k] = 0;
    if(match[k] == -1) return (0);
    match[match[k]] = -1;
    ++timestamp;
    int ret = dfs(match[k]);
    match[k] = -1;
    return (ret - 1);
  }

};


const int dx[] = {-1, 0, 1};
const int dy[][3] = {{0, -1, 0},
                     {0, 1,  0}};

const int vx[2][5][3] = {
    {{1, 2, 3}, {1, 1, 2}, {1, 1, 2}},
    {{1, 2, 3}, {1, 1, 2}, {0, 1, 1}, {1, 1, 2}, {0, 1, 1}},

};
const int vy[2][5][3] = {
    {{0, 0, 0}, {0,  1, 1},  {0, 1,  0}},
    {{0, 0, 0}, {-1, 0, -1}, {1, -1, 0}, {-1, 0, 0}, {1, 1, 2}}
};

bool check(int *x, int *y)
{
  vector< pair< int, int > > s(4);
  for(int i = 0; i < 4; i++) s[i] = {x[i], y[i]};
  sort(begin(s), end(s));
  s.erase(unique(begin(s), end(s)), end(s));
  if(s.size() == 3) return (false);

  bool mod = (s[0].first + s[0].second) % 2 != 0;
  for(int i = 0; i < 5; i++) {
    bool flag = true;
    for(int j = 1; j < s.size(); j++) {
      if(s[j].first - s[0].first != vx[mod][i][j - 1]) flag = false;
      if(s[j].second - s[0].second != vy[mod][i][j - 1]) flag = false;
    }
    if(flag) return (true);
  }
  return (false);
}

int main()
{
  int N;
  int x[5000][4], y[5000][4];

  while(scanf("%d", &N), N) {

    int failed_count = 0;
    vector< pair< int, int > > enable[N], press;
    for(int i = 0; i < N; i++) {
      for(int j = 0; j < 3; j++) {
        scanf("%d %d", &x[i][j], &y[i][j]);
      }
      for(int j = 0; j < 3; j++) {
        for(int k = 0; k < 3; k++) {
          x[i][3] = x[i][j] + dx[k];
          y[i][3] = y[i][j] + dy[(x[i][j] + y[i][j]) % 2 != 0][k];
          if(check(x[i], y[i])) enable[i].emplace_back(x[i][3], y[i][3]);
        }
      }

      sort(begin(enable[i]), end(enable[i]));
      enable[i].erase(unique(begin(enable[i]), end(enable[i])), end(enable[i]));
      for(auto &p : enable[i]) press.emplace_back(p);
      if(enable[i].empty()) failed_count++;
    }
    sort(begin(press), end(press));
    press.erase(unique(begin(press), end(press)), end(press));
    Bipartite_Matching flow(N + press.size());
    for(int i = 0; i < N; i++) {
      for(auto &p : enable[i]) {
        auto s = lower_bound(begin(press), end(press), p) - begin(press);
        flow.add_edge(i, N + s);
      }
    }
    int cnt = 0;

    for(int i = 0; i < N; i++) {
      for(int j = 0; j < 3; j++) {
        auto q = make_pair(x[i][j], y[i][j]);
        auto p = lower_bound(begin(press), end(press), q);
        if(p == end(press)) continue;
        if(*p == q) flow.kill(N + p - begin(press)), ++cnt;
      }
    }
    auto match = flow.bipartite_matching();
    if(match == N) {
      puts("Valid");
    } else {
      vector< int > ret;
      if(failed_count <= 1 && match >= N - 4) {
        for(int i = 0; i < N; i++) {
          for(int j = 0; j < 3; j++) {
            auto q = make_pair(x[i][j], y[i][j]);
            auto p = lower_bound(begin(press), end(press), q);
            if(p == end(press)) continue;
            if(*p == q) match += flow.add(N + p - begin(press));
          }
          match += flow.kill(i);
          if(match == N - 1) ret.push_back(i);
          match += flow.add(i);
          for(int j = 0; j < 3; j++) {
            auto q = make_pair(x[i][j], y[i][j]);
            auto p = lower_bound(begin(press), end(press), q);
            if(p == end(press)) continue;
            if(*p == q) match += flow.kill(N + p - begin(press));
          }
        }
      }

      if(ret.empty()) {
        puts("Invalid");
      } else {
        puts("Remove");
        for(int k : ret) printf("%d\n", k + 1);
      }
    }
  }
}
accuracy: 1
time_ms: 4190
memory_kb: 5116
final_rank: 3

code_snippet: #include<stdio.h>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<string.h>
#include<queue>
using namespace std;
const int D_MAX_V=30002;
const int D_v_size=30002;
int V;
const int MAX_V=30002;
vector<int>G[MAX_V];
int mc[MAX_V];
int match[MAX_V];
bool used[MAX_V];
int ava[MAX_V];
void add_edge(int u,int v){
	G[u].push_back(v);
	G[v].push_back(u);
}
bool dfs2(int v){
	used[v]=true;
	for(int i=0;i<G[v].size();i++){
		int u=G[v][i],w=match[u];
		if(!ava[u])continue;
		if(w<0||!used[w]&&dfs2(w)){
			match[v]=u;match[u]=v;return true;
		}
	}
	return false;
}
int b_m(){
	int res=0;
	memset(match,-1,sizeof(match));
	for(int v=0;v<V;v++){
		if(match[v]<0&&ava[v]){
			memset(used,0,sizeof(used));
			if(dfs2(v))res++;
		}
	}
	return res;
}

int x[5100][5];
int y[5100][5];
vector<pair<int,int> > ad[5100];
vector<int> w[5100];
int dx[7][4]={{-1,0,1,0},{-1,0,1,0},{-1,0,0,1},{1,0,0,-1},{0,0,1,1},{0,0,1,1},{-1,0,1,2}};
int dy[7][4]={{0,0,0,1},{0,0,0,-1},{0,0,1,1},{0,0,1,1},{-1,0,0,1},{1,0,0,-1},{0,0,0,0}};
int dr[7]={1,0,1,1,0,1,2};
int ABS(int a){return max(a,-a);}
pair<int,int>le[25000];
int main(){
	int a;
	while(scanf("%d",&a),a){
		map<pair<int,int>,int>m;
		map<pair<int,int>,int>m2;
		int sz=0;
		for(int i=0;i<a;i++)ad[i].clear();
		for(int i=0;i<a;i++)w[i].clear();
		for(int i=0;i<a;i++){
			for(int j=0;j<3;j++){
				scanf("%d%d",&x[i][j],&y[i][j]);
				m2[make_pair(x[i][j],y[i][j])]=i;
			}
		}
		int mu=0;
		int mat=-1;
		for(int i=0;i<a;i++){
			int U=999999;
			int D=-999999;
			int L=999999;
			int R=-999999;
			for(int j=0;j<3;j++){
				U=min(U,y[i][j]);D=max(D,y[i][j]);L=min(L,x[i][j]),R=max(R,x[i][j]);
			}
			if(D-U>2||R-L>3)continue;
			for(int j=L-1;j<=R+1;j++){
				for(int k=U-1;k<=D+1;k++){
					set<pair<int,int> >S;
					int X=0;int Y=0;
					for(int l=0;l<3;l++){
						X+=x[i][l];Y+=y[i][l];
						S.insert(make_pair(x[i][l],y[i][l]));
					}
					X+=j;Y+=k;
					S.insert(make_pair(j,k));
					if(S.size()!=4)continue;
					bool ok=false;
					int ax=(X+1)/4;if(X<0)ax=-((ABS(X)+2)/4);
					int ay=(Y+1)/4;if(Y<0)ay=-((ABS(Y)+2)/4);
					for(int l=0;l<7;l++){
						bool OK=true;
						if(dr[l]!=2&&ABS(ax+ay)%2!=dr[l])continue;
						for(int ii=0;ii<4;ii++){
							if(S.count(make_pair(ax+dx[l][ii],ay+dy[l][ii]))==0)OK=false;
						}
						if(OK)ok=true;
					}
					if(ok){
						ad[i].push_back(make_pair(j,k));
						if(m.count(make_pair(j,k))==0){
							le[sz]=make_pair(j,k);
							m[make_pair(j,k)]=sz++;
						}
					}
				}
			}
			if(ad[i].size()==0){
				mu++;
				mat=i;
			}
		}
		if(mu>1){
			printf("Invalid\n");continue;
		}
		V=sz+a;
		for(int i=0;i<sz+a;i++){
			G[i].clear();
			ava[i]=1;
		}
		for(int i=0;i<a;i++){
			for(int j=0;j<ad[i].size();j++){
		//		printf("(%d, %d) ",ad[i][j].first,ad[i][j].second);
				add_edge(i+sz,m[ad[i][j]]);
				if(m2.count(ad[i][j])){
					bool ok=true;
					for(int k=0;k<w[m2[ad[i][j]]].size();k++)if(w[m2[ad[i][j]]][k]==m[ad[i][j]]){ok=false;break;}
					if(ok)w[m2[ad[i][j]]].push_back(m[ad[i][j]]);
				}
			}
			//printf("\n");
		}
		for(int i=0;i<sz;i++){
			if(m2.count(le[i]))ava[i]=0;
		}
		int now=b_m();
		if(now==a){
			printf("Valid\n");continue;
		}
		if(now<a-4){
			printf("Invalid\n");continue;
		}
		vector<int>sp;
		for(int i=0;i<a;i++)if(match[i+sz]==-1)sp.push_back(i);
		vector<int>can;
		
		for(int i=0;i<a;i++){
			if(mu&&mat!=i)continue;
			ava[sz+i]=0;
			int rev=-1;
			int mtc=now;
			for(int j=0;j<sz+a;j++)mc[j]=match[j];
			if(~match[sz+i]){
				mtc--;
				rev=match[sz+i];
				match[match[sz+i]]=-1;
				match[sz+i]=-1;
			}
			for(int j=0;j<w[i].size();j++){
				ava[w[i][j]]=1;
			}
			for(int j=0;j<sp.size();j++){
				if(sp[j]==i)continue;
				memset(used,0,sizeof(used));
				if(dfs2(sp[j]+sz)){
					mtc++;
				}
			}
			if(mtc==a-1)can.push_back(i);
			for(int j=0;j<sp.size();j++){
				if(~match[sp[j]+sz]){
					match[match[sp[j]+sz]]=-1;
					match[sp[j]+sz]=-1;
				}
			}
			ava[sz+i]=1;
			if(~rev){
				match[rev]=sz+i;
			}
			match[sz+i]=rev;
			for(int j=0;j<w[i].size();j++){
				if(~match[w[i][j]]){
					match[match[w[i][j]]]=-1;
					match[w[i][j]]=-1;
				}
				ava[w[i][j]]=0;
			}
			for(int j=0;j<sz+a;j++)match[j]=mc[j];
		}
		if(can.size()){
			printf("Remove\n");
			for(int i=0;i<can.size();i++)printf("%d\n",can[i]+1);
		}else printf("Invalid\n");
	}
}
accuracy: 1
time_ms: 4520
memory_kb: 5936
final_rank: 4

code_snippet: #include <cstdio>
#include <vector>
#include <array>
#include <algorithm>
using namespace std;


const int inf = (int)1e8;

struct Edge {
    int to, rev, cap;
};

struct Graph {

    vector<vector<Edge> > g;
    int gs, gt;

    void initialize(int n, int s, int t)
    {
        g.resize(n);
        fill(g.begin(), g.end(), vector<Edge>());
        gs = s;
        gt = t;
    }

    void add_edge(int from, int to)
    {
        g[from].push_back({to, (int)g[to].size(), 1});
        g[to].push_back({from, (int)g[from].size() - 1, 0});
    }

    bool flow_dfs(int v, int t, vector<bool> &used)
    {
        if(v == t)
            return true;
        used[v] = true;

        for(auto &e : g[v]) {

            if(used[e.to] || e.cap <= 0)
                continue;

            const bool f = flow_dfs(e.to, t, used);
            if(!f)
                continue;

            e.cap -= 1;
            g[e.to][e.rev].cap += 1;

            return true;
        }

        return false;
    }

    int max_flow_step(int s, int t)
    {
        static vector<bool> used;

        if(g.size() > used.size())
            used.resize(g.size());
        fill(used.begin(), used.end(), false);

        return flow_dfs(s, t, used);
    }

    int max_flow()
    {
        int flow = 0;

        while(true) {

            const bool f = max_flow_step(gs, gt);
            if(f)
                flow += 1;
            else
                break;
        }

        return flow;
    }

    void restore_edge(int from, int to)
    {
		//printf("restore: %d -> %d\n", from, to);

        for(auto &e : g[from]) {
            if(e.to != to)
                continue;
            e.cap += 1;
            return;
        }

        add_edge(from, to);
    }

    int remove_edge(int from, int to)
    {
		//printf("remove: %d -> %d\n", from, to);

        for(auto &e : g[from]) {

            if(e.to != to)
                continue;

            auto &re = g[to][e.rev];

			if(e.cap >= 1) {
				e.cap -= 1;
				return 0;
			}

	        const int f = max_flow_step(from, to);

			if(f >= 1) {
				re.cap -= 1;
				return 0;
			}

			max_flow_step(from, gs);
	        max_flow_step(gt, to);
	        re.cap -= 1;

			return 1;
        }

        return 0;
    }
};


typedef array<pair<int, int>, 3> TempTiles;
array<TempTiles, 8> temps;
array<bool, 8> is_up;

void set_temps(int k, int x1, int y1, int x2, int y2, int x3, int y3, bool up)
{
	is_up[k] = up;
	temps[k][0] = {x1, y1};
	temps[k][1] = {x2, y2};
	temps[k][2] = {x3, y3};
}

void initialize_temps()
{
	set_temps(0, 1, 0, 2, 0, 1, 1, true);
	set_temps(1, 1, 0, 2, 0, 1, -1, false);
	set_temps(2, 1, 0, 2, 0, 3, 0, true);
	set_temps(3, 1, 0, 2, 0, 3, 0, false);
	set_temps(4, 1, 0, 1, 1, 2, 1, true);
	set_temps(5, 0, 1, 1, 1, 1, 2, false);
	set_temps(6, 0, 1, 1, 0, 1, -1, false);
	set_temps(7, 1, 0, 1, -1, 2, -1, false);
}


bool is_valid(const array<pair<int, int>, 4> &tiles)
{
	pair<int, int> pivot = *min_element(tiles.begin(), tiles.end());
	bool up = (pivot.first + pivot.second) % 2 == 0;

	for(int temp_idx = 0; temp_idx < (int)temps.size(); ++temp_idx) {

		if(is_up[temp_idx] != up)
			continue;
		const auto temp = temps[temp_idx];

		bool ok = true;

		for(const auto &t : tiles) {

			bool exist = false;
			const int x = t.first - pivot.first;
			const int y = t.second - pivot.second;
			const pair<int, int> xy = {x, y};

			if(x == 0 && y == 0)
				continue;

			for(const auto u : temp) {
				if(u == xy)
					exist = true;
			}

			if(!exist)
				ok = false;
		}

		if(ok)
			return true;
	}

	return false;
}


int main()
{
	initialize_temps();

	while(true) {

		int n;

		scanf("%d", &n);
		if(n == 0)
			break;

		Graph g;
		vector<vector<pair<int, int> > > candy(n);
		vector<array<pair<int, int>, 3> > pretiles(n);
		vector<array<int, 3> > pretiles_pos(n);
		vector<pair<int, int> > pos;

		for(int tile_idx = 0; tile_idx < n; ++tile_idx) {

			const int dxs[] = {-1, 0, 1, -1, 0, 1};
			const int dys[] = {0, -1, 0, 0, 1, 0};
			array<pair<int, int>, 4> tiles;
			array<pair<int, int>, 9> xy4s;

			pair<int, int> infinf = {inf, inf};
			fill(xy4s.begin(), xy4s.end(), infinf);

			for(int i = 0; i < 3; ++i) {
				int x, y;
				scanf("%d%d", &x, &y);
				pretiles[tile_idx][i] = tiles[i] = {x, y};
			}

			for(int i = 0; i < 3; ++i) {
				for(int j = 0; j < 3; ++j) {

					const int idx = (tiles[i].first + tiles[i].second) & 1;
					const int x4 = dxs[idx * 3 + j] + tiles[i].first;
					const int y4 = dys[idx * 3 + j] + tiles[i].second;
					const pair<int, int> xy4 = {x4, y4};
					bool ok = true;

					for(int k = 0; k < 3; ++k) {
						if(xy4 == tiles[k])
							ok = false;
					}
					for(int k = 0; k < i * 3 + j; ++k) {
						if(xy4 == xy4s[k])
							ok = false;
					}

					if(!ok)
						continue;
					xy4s[i * 3 + j] = xy4;
				}
			}

			for(const auto xy4 : xy4s) {
				if(xy4.first == inf)
					continue;
				tiles[3] = xy4;
				if(is_valid(tiles))
					candy[tile_idx].push_back(xy4);
			}

			/*printf("tile %d:\n", tile_idx);
			for(auto xy : candy[tile_idx])
				printf("%d %d\n", xy.first, xy.second);*/
		}

		for(const auto &cc : candy) {
			for(const auto &c : cc)
				pos.push_back(c);
		}

		sort(pos.begin(), pos.end());
		pos.erase(unique(pos.begin(), pos.end()), pos.end());
		const int gs = 0, gt = 1 + n + pos.size();
		g.initialize(2 + n + pos.size(), gs, gt);

		for(int v = 0; v < n; ++v) {
			for(int i = 0; i < 3; ++i) {
				const auto &xy = pretiles[v][i];
				int w = lower_bound(pos.begin(), pos.end(), xy) - pos.begin();
				bool exist = (w < (int)pos.size()) && (pos[w] == xy);
				pretiles_pos[v][i] = exist ? w : -1;
			}
		}
		for(int v = 0; v < n; ++v) {
			g.add_edge(gs, 1 + v);
			for(const auto &c : candy[v]) {
				int w = lower_bound(pos.begin(), pos.end(), c) - pos.begin();
				g.add_edge(1 + v, 1 + n + w);
			}
		}
		for(int w = 0; w < (int)pos.size(); ++w)
			g.add_edge(1 + n + w, gt);
		for(int v = 0; v < n; ++v) {
			for(const auto w : pretiles_pos[v]) {
				if(w != -1)
					g.remove_edge(1 + n + w, gt);
			}
		}

		int f = g.max_flow();
		int diff = n - f;

		if(diff == 0) {
			printf("Valid\n");
			continue;
		}

		static vector<int> ans;
		ans.resize(0);

		for(int rv = 0; rv < n; ++rv) {

			int restored = 0;

			for(const auto w : pretiles_pos[rv]) {
				if(w != -1)
					restored += 1;
			}

			if(restored < (diff - 1))
				continue;

			for(const auto w : pretiles_pos[rv]) {
				if(w != -1)
					g.restore_edge(1 + n + w, gt);
			}
			f -= g.remove_edge(gs, 1 + rv);

			f += g.max_flow();
			if(f == n - 1)
				ans.push_back(rv);

			g.restore_edge(gs, 1 + rv);
			for(const auto w : pretiles_pos[rv]) {
				if(w != -1)
					f -= g.remove_edge(1 + n + w, gt);
			}
		}

		if(ans.size() == 0) {
			printf("Invalid\n");
		} else {
			printf("Remove\n");
			for(auto v : ans)
				printf("%d\n", v + 1);
		}
	}

	return 0;
}
accuracy: 1
time_ms: 4200
memory_kb: 3456
final_rank: 1

code_snippet: #include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#include<map>
#include<tuple>
#include<cstring>
#include<cassert>

using namespace std;

typedef pair<int, int> P;
#define X first
#define Y second
#define pb push_back
#define REP(i,n) for(int i=0;i<(int)n;i++)
#define ALL(p) p.begin(), p.end()

P operator+(const P& p, const P& q){ return P(p.X+q.X, p.Y+q.Y); }
P operator-(const P& p, const P& q){ return P(p.X-q.X, p.Y-q.Y); }
ostream &operator<<(ostream &os, P p){
	return os << "(" << p.X << ", " << p.Y << ")";
}
P dir[2][3] = {
	{{1,0}, {-1,0}, {0,-1}}
, 
	{{0,1}, {-1,0}, {1,0}}
};

P valids[2][5][3] = {{
	{{1, 0}, {2, 0}, {3, 0}},
	{{1, 0}, {1, 1}, {2, 1}},
	{{1, 0}, {1, 1}, {2, 0}}
}, {
	{{1, 0}, {2, 0}, {3, 0}},
	{{1, -1}, {1, 0}, {2, -1}},
	{{0, 1}, {1, -1}, {1, 0}},
	{{1, -1}, {1, 0}, {2, 0}},
	{{0, 1}, {1, 1}, {1, 2}}
}};

template<typename T>
struct Serializer{
	map<T, int> se;
	vector<T> idx;
	Serializer(){}
	int operator()(const T &v){
		auto it = se.find(v);
		if(it != se.end()) return it->second;
		idx.pb(v);
		return se[v] = idx.size()-1;
	}
	T& operator[](const int i){
		return idx[i];
	}
	int find(const T &v){
		auto it = se.find(v);
		if(it != se.end()) return it->second;
		return -1;
	}
	size_t size() const{
		return se.size();
	}
};

int n, m;

int check(vector<P> p){
	sort(ALL(p));
	int f = !!((p[0].X+p[0].Y)%2);
	REP(i, 5){
		if([&](){
			REP(j, 3) if(p[j+1]-p[0] != valids[f][i][j]) return false;
			return true;
		}()) return true;
	}
	return false;
}

P move(P p, int d){
	return p + dir[!!((p.X+p.Y)%2)][d];
}

int match[21000], used[21000], invalid[21000];
int timestamp;
bool bipartite_matching_dfs(int v, const vector<vector<int>> &g){
	used[v] = timestamp;
	for(int u : g[v])if(!invalid[u]){
		int w = match[u];
		if(w < 0 || (used[w] != timestamp && bipartite_matching_dfs(w, g))){
			match[v] = u;
			match[u] = v;
			return true;
		}
	}
	return false;
}

int bipartite_matching(const vector<vector<int>> &g){
	int res = 0;
	memset(match, -1, sizeof(match));
	REP(v, g.size())if(match[v] < 0 && !invalid[v]){
		++ timestamp;
		if(bipartite_matching_dfs(v, g)) res ++;
	}
	return res;
}

int erase(int v, const vector<vector<int>> &g){
	assert(invalid[v] == 0);
	invalid[v] = 1;
	if(match[v] == -1) return 0;
	match[match[v]] = -1;
	++ timestamp;
	int res = bipartite_matching_dfs(match[v], g) - 1;
	match[v] = -1;
	return res;
}

int add(int v, const vector<vector<int>> &g){
	assert(invalid[v] == 1);
	invalid[v] = 0;
	++ timestamp;
	return bipartite_matching_dfs(v, g);
}

int main(){
	while(scanf("%d", &n), n){
		vector<vector<P>> p;
		vector<vector<int>> g(n);
		Serializer<P> se;
		int f = -1;
		REP(i, n){
			p.emplace_back(3);
			REP(j, 3) scanf("%d%d", &p[i][j].first, &p[i][j].second);
			REP(j, 3)REP(k, 3){
				p[i].pb(move(p[i][j], k));
				if(check(p[i])) g[i].pb(n + se(p[i][3]));
				p[i].pop_back();
			}
			sort(ALL(g[i])); g[i].erase(unique(ALL(g[i])), g[i].end());
			if(g[i].empty()) f = (f == -1) ? i : -2;
		}
		g.resize(n + se.size());
		memset(invalid, 0, sizeof(invalid));
		REP(u, n){
			for(int &v : g[u]) g[v].pb(u);
			REP(j, 3){
				int x = se.find(p[u][j]);
				if(x >= 0) invalid[n+x] = 1;
			}
		}
		int matching = bipartite_matching(g);
		if(matching < n-4 || f == -2){
			puts("Invalid");
		}else if(matching == n){
			puts("Valid");
		}else{
			vector<int> ans;
			REP(i, n)if(f == -1 || f == i){
				REP(j, 3){
					int x = se.find(p[i][j]);
					if(x >= 0) matching += add(n+x, g);
				}
				matching += erase(i, g);
				if(matching == n-1) ans.pb(i+1);
				matching += add(i, g);
				REP(j, 3){
					int x = se.find(p[i][j]);
					if(x >= 0) matching += erase(n+x, g);
				}
			}
			if(ans.empty()) puts("Invalid");
			else{
				puts("Remove");
				for(int v : ans) printf("%d\n", v);
			}
		}
	}
	return 0;
}
accuracy: 1
time_ms: 5360
memory_kb: 4252
final_rank: 5

code_snippet: #include <iostream>
#include <iomanip>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <complex>
#include <cstring>
#include <cstdlib>
#include <string>
#include <cmath>
#include <cassert>
#include <queue>
#include <set>
#include <map>
#include <valarray>
#include <bitset>
#include <stack>
using namespace std;

#define REP(i,n) for(int i=0;i<(int)n;++i)
#define FOR(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();++i)
#define ALL(c) (c).begin(), (c).end()
#define chmax(a,b) (a<(b)?(a=b,1):0)
#define chmin(a,b) (a>(b)?(a=b,1):0)
#define valid(y,x,h,w) (0<=y&&y<h&&0<=x&&x<w)
const int INF = 1<<29;
const double EPS = 1e-8;
const double PI = acos(-1);
typedef pair<int,int> pii;
typedef long long ll;

const int dy[2][3] = {-1,0,0,1,0,0};
const int dx[2][3] = {0,-1,1,0,-1,1};

struct Tetra {
  bool d;
  /*
    d=0:    d=1:
    a1△a2    a0
      a0    a1▽a2
   */
  int b;
  int a0,a1,a2;
  int x, y;
  Tetra(int b, int a0, int a1, int a2, int x, int y) :
    b(b),a0(a0),a1(a1),a2(a2),x(x),y(y) {
    d = (x+y&1);
  }
  void rotate(int &a, int &b, int &c, int &d) {
    int t=a; a=b;b=c;c=d;d=t;
  }
  void roll(int dir) {
    if (dir == 0) swap(a0,b);              // y
    else if (dir == 1) rotate(b,a2,a0,a1); // +x
    else rotate(b,a1,a0,a2);               // -x
    y += dy[d][dir];
    x += dx[d][dir];    
    d = !d;
  }
  bool operator<(const Tetra &rhs) const {
    return pii(x,y) < pii(rhs.x,rhs.y);
  }
};

vector<pii> lastOne(const vector<int> &xs, const vector<int> &ys) {
  set<pii> ps,neighbor;
  REP(i,3) {
    ps.insert(pii(ys[i],xs[i]));
    bool d = xs[i]+ys[i]&1;
    REP(j,3) {
      int yy = ys[i]+dy[d][j];
      int xx = xs[i]+dx[d][j];
      neighbor.insert(pii(yy,xx));
    }
  }
  
  vector<pii> res;
  FOR(it, neighbor) {
    set<pii> tps = ps;
    tps.insert(pii(it->first,it->second));    

    Tetra ini(0,1,2,3,xs[0],ys[0]);
    queue<Tetra> Q;
    set<pii> visited;
    Q.push(ini);
    visited.insert(pii(ys[0],xs[0]));
    set<int> bs;
    while(!Q.empty()) {
      Tetra p = Q.front(); Q.pop();
      bs.insert(p.b);
      REP(i,3) {
        Tetra nxt = p;
        nxt.roll(i);
        if (!visited.count(pii(nxt.y,nxt.x)) && tps.count(pii(nxt.y, nxt.x))) {
          Q.push(nxt);
          visited.insert(pii(nxt.y, nxt.x));
        }
      }
    }
    if (bs.size() == 4) {
      res.push_back(*it);
    }
  }
  return res;
}

typedef int Weight;
struct Edge {
  int src, dst;
  Weight weight;
  Edge(int src, int dst, Weight weight) :
    src(src), dst(dst), weight(weight) { }
  Edge(int src, int dst) : src(src), dst(dst) {}
};

bool operator < (const Edge &e, const Edge &f) {
  return e.weight != f.weight ? e.weight > f.weight : // !!INVERSE!!
    e.src != f.src ? e.src < f.src : e.dst < f.dst;
}

typedef vector<Edge> Edges;
typedef vector<Edges> Graph;

bool valid[50000];

bool augment(const Graph& g, int u,
    vector<int>& matchTo, vector<bool>& visited) {
  if (u < 0) return true;
  FOR(e, g[u]) if (!visited[e->dst] && valid[e->dst]) {
    visited[e->dst] = true;
    if (augment(g, matchTo[e->dst], matchTo, visited)) {
      matchTo[e->src] = e->dst;
      matchTo[e->dst] = e->src;
      return true;
    }
  }
  return false;
}

int bipartiteMatching(const Graph& g, int L, vector<int> &matchTo) {
  const int n = g.size();
  int match = 0;
  REP(u, L) {
    if (!valid[u] || matchTo[u] != -1) continue;
    vector<bool> visited(n);
    if (augment(g, u, matchTo, visited)) ++match;
  }
  return match;
}


int main() {
  int n;
  while(cin >> n, n) {
    vector<vector<int> > xss,yss;
    vector<vector<pii> > vs;
    map<pii,int> mp;
    int num = 0;
    REP(i,n) {
      vector<int> xs,ys;
      REP(j,3) {
        int x,y;
        cin >> x  >> y;
        xs.push_back(x);
        ys.push_back(y);
      }
      xss.push_back(xs);
      yss.push_back(ys);
      vector<pii> v = lastOne(xs,ys);
      vs.push_back(v);
      FOR(it, v) if (mp.count(*it) == 0) mp[*it] = num++;
      // cout << i << " : ";
      // FOR(it, v) printf("(%d,%d) ", it->second, it->first);
      // cout << endl;
    }
    Graph g(n+num);
    REP(i,n+num) valid[i] = 1;
    REP(i, n) {
      FOR(jt, vs[i]) {
        int dst = n+mp[*jt];
        g[i].push_back(Edge(i,dst,1));
        g[dst].push_back(Edge(dst,i,1));
      }
      REP(j,3) {
        pii p(yss[i][j], xss[i][j]);
        if (mp.count(p)) {
          valid[n+mp[p]] = 0;
        }
      }
    }
    vector<int> allMatchTo(g.size(), -1);
    int allMatch = bipartiteMatching(g,n,allMatchTo);
    if (allMatch == n) {
      puts("Valid");
      continue;
    } else if (allMatch < n-4) {
      puts("Invalid");
      continue;
    }
    vector<int> ans;
    REP(i,n) {
      vector<int> matchTo = allMatchTo;
      int match = allMatch;
      
      int dst = matchTo[i];
      if (dst != -1) {
        matchTo[i] = matchTo[dst] = -1;
        match--;
      }
      REP(j,3) {
        pii p(yss[i][j], xss[i][j]);
        if (mp.count(p)) {
          valid[n+mp[p]] = 1;
        }
      }
      valid[i] = 0;

      // cout << allMatch << " " << match << " ";
      match += bipartiteMatching(g,n,matchTo);
      if (match == n-1) {
        ans.push_back(i);
      }
      // cout << match << endl;
      // 戻す
      if (dst != -1) {
        matchTo[i] = dst;
        matchTo[dst] = i;
      }
      REP(j,3) {
        pii p(yss[i][j], xss[i][j]);
        if (mp.count(p)) {
          valid[n+mp[p]] = 0;
        }
      }
      valid[i] = 1;      
    }
    if (ans.size()) {
      puts("Remove");
      FOR(it, ans) cout << *it+1 << endl;
    }else {
      puts("Invalid");
    }
  }
}
accuracy: 1
time_ms: 4340
memory_kb: 4588
final_rank: 2