Problem:
Cube Dividing
Pablo Cubarson is a well-known cubism artist. He is producing a new piece of work using a cuboid which consists of $A \times B \times C$ unit cubes. He plans to make a beautiful shape by removing $N$ units cubes from the cuboid. When he is about to begin the work, he has noticed that by the removal the cuboid may be divided into several parts disconnected to each other. It is against his aesthetics to divide a cuboid. So he wants to know how many parts are created in his plan.
Your task is to calculate the number of connected components in the cuboid after removing the $N$ cubes. Two cubes are connected if they share one face.
Input
The input consists of a single test case. The test case is formatted as follows:
$A$ $B$ $C$ $N$
$X_1$ $Y_1$ $Z_1$
...
$X_N$ $Y_N$ $Z_N$
The first line contains four integers $A$, $B$, $C$ and $N$. $A$, $B$ and $C$ ($1 \leq  A,B,C \leq 10^6$) denote the size of the cuboid $-$ the cuboid has an $A$ unit width from left to right and a $B$ unit height from bottom to top, and a $C$ unit depth from front to back. $N$ ($0 \leq N \leq 20,000, N \leq A \times B \times C - 1$) denotes the number of the cubes removed in the Cubarson's plan. Each of the following $N$ lines contains three integers $X_i$ ($0 \leq X_i \leq A-1$), $Y_i$ ($0 \leq Y_i \leq B-1$) and $Z_i$ ($0 \leq Z_i \leq C - 1$). They denote that the cube located at the $X_i$-th position from the left, the $Y_i$-th from the bottom and the $Z_i$-th from the front will be removed in the plan. You may assume the given positions are distinct.
Output
Print the number of the connected components in the cuboid after removing the specified cubes.
Sample Input 1
2 2 2 4
0 0 0
1 1 0
1 0 1
0 1 1
Output for the Sample Input 1
4
Sample Input 2
3 3 3 1
1 1 1
Output for the Sample Input 2
1
Sample Input 3
1 1 3 2
0 0 0
0 0 2
Output for the Sample Input 3
1

Submitted solutions:

code_snippet: // AOJ #2733 Cube Dividing
// 2025.3.23

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

#define gc() getchar_unlocked()
#define pc(c) putchar_unlocked(c)

int Cin() {  // 整数の入力
	int n = 0; int c = gc();
	if (c == '-') {	c = gc();
		do n = 10*n + (c & 0xf), c = gc(); while (c >= '0');
		return -n;
	}
	do n = 10*n + (c & 0xf), c = gc(); while (c >= '0');
	return n;
}

void Cout(ll n) { // 整数の表示（出力）
	char b[30];
	if (!n) pc('0');
	else {
		if (n < 0) pc('-'), n = -n;
		int i = 0; while (n) b[i++] = n % 10 + '0', n /= 10;
		while (i--) pc(b[i]);
	}
	pc('\n');
}

typedef pair<int, int> pi;

const int MAXN = 505;
const int dx[6] = {1, -1, 0, 0, 0, 0};
const int dy[6] = {0, 0, 1, -1, 0, 0};
const int dz[6] = {0, 0, 0, 0, 1, -1};

struct disj{
	int pa[1000005];
	void init(int n){
		iota(pa, pa + n + 1, 0);
	}
	int find(int x){
		return pa[x] = (pa[x] == x ? x : find(pa[x]));
	}
	bool uni(int p, int q){
		p = find(p);
		q = find(q);
		if(p == q) return 0;
		pa[q] = p; return 1;
	}
}disj;

int getcmp(vector<tuple<int, int, int>> v){
	disj.init(v.size());
	int ans = v.size();
	for(int i=0; i<v.size(); i++){
		int x, y, z;
		tie(x, y, z) = v[i];
		for(int j=0; j<6; j++){
			auto w = make_tuple(x + dx[j], y + dy[j], z + dz[j]);
			int pos = lower_bound(v.begin(), v.end(), w) - v.begin();
			if(pos < v.size() && v[pos] == w) ans-= disj.uni(i, pos);
		}
	}
	return ans;
}

vector<int> pos[1000005];

int main(){
	int a = Cin(), b = Cin(), c = Cin(), n = Cin();

    vector<tuple<int, int, int>> v, w;
	disj.init(n);

	auto ok = [&](int x, int y, int z){
		return 0 <= x && x < a && 0 <= y && y < b && 0 <= z && z < c;
	};

	for(int i=0; i<n; i++){
        int x = Cin(), y = Cin(), z = Cin();
		v.emplace_back(x, y, z);
	}
	sort(v.begin(), v.end());
	for(int i=0; i<v.size(); i++){
		int x, y, z;
		tie(x, y, z) = v[i];
		for(int a=-1; a<=1; a++){
			for(int b=-1; b<=1; b++){
				for(int c=-1; c<=1; c++){
					auto pos = lower_bound(v.begin(), v.end(), make_tuple(x+a, y+b, c+z)) - v.begin();
					if(pos < v.size() && v[pos] == make_tuple(x+a, y+b, c+z)) disj.uni(i, pos);
				}
			}
		}
	}
	for(int i=0; i<v.size(); i++){
		pos[disj.find(i)].push_back(i);
	}
	int ans = 1;
	for(int i=0; i<v.size(); i++){
		if(pos[i].size()){
			vector<tuple<int, int, int>> tp;
			for(auto &j : pos[i]){
				int x, y, z;
				tie(x, y, z) = v[j];
				for(int dx=-1; dx<=1; dx++){
					for(int dy=-1; dy<=1; dy++){
						for(int dz=-1; dz<=1; dz++){
							auto p = make_tuple(x + dx, y + dy, z + dz);
							if(!binary_search(v.begin(), v.end(), p) && ok(get<0>(p), get<1>(p), get<2>(p))){
								tp.push_back(p);
							}
						}
					}
				}
			}
			sort(tp.begin(), tp.end());
			tp.resize(unique(tp.begin(), tp.end()) - tp.begin());
			ans += getcmp(tp) - 1;
		}
	}
	Cout(ans);
    return 0;
}
accuracy: 1
time_ms: 120
memory_kb: 34604
final_rank: 3

code_snippet: // AOJ #2733 Cube Dividing
// 2025.3.23

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

typedef pair<int, int> pi;

const int MAXN = 505;
const int dx[6] = {1, -1, 0, 0, 0, 0};
const int dy[6] = {0, 0, 1, -1, 0, 0};
const int dz[6] = {0, 0, 0, 0, 1, -1};

struct disj{
	int pa[1000005];
	void init(int n){
		iota(pa, pa + n + 1, 0);
	}
	int find(int x){
		return pa[x] = (pa[x] == x ? x : find(pa[x]));
	}
	bool uni(int p, int q){
		p = find(p);
		q = find(q);
		if(p == q) return 0;
		pa[q] = p; return 1;
	}
}disj;

int getcmp(vector<tuple<int, int, int>> v){
	disj.init(v.size());
	int ans = v.size();
	for(int i=0; i<v.size(); i++){
		int x, y, z;
		tie(x, y, z) = v[i];
		for(int j=0; j<6; j++){
			auto w = make_tuple(x + dx[j], y + dy[j], z + dz[j]);
			int pos = lower_bound(v.begin(), v.end(), w) - v.begin();
			if(pos < v.size() && v[pos] == w) ans-= disj.uni(i, pos);
		}
	}
	return ans;
}

int n, a, b, c;
vector<int> pos[1000005];

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

	vector<tuple<int, int, int>> v, w;
	cin >> a >> b >> c >> n;
	disj.init(n);
	auto ok = [&](int x, int y, int z){
		return 0 <= x && x < a && 0 <= y && y < b && 0 <= z && z < c;
	};
	for(int i=0; i<n; i++){
        int x, y, z;
		cin >> x >> y >> z;
		v.emplace_back(x, y, z);
	}
	sort(v.begin(), v.end());
	for(int i=0; i<v.size(); i++){
		int x, y, z;
		tie(x, y, z) = v[i];
		for(int a=-1; a<=1; a++){
			for(int b=-1; b<=1; b++){
				for(int c=-1; c<=1; c++){
					auto pos = lower_bound(v.begin(), v.end(), make_tuple(x+a, y+b, c+z)) - v.begin();
					if(pos < v.size() && v[pos] == make_tuple(x+a, y+b, c+z)) disj.uni(i, pos);
				}
			}
		}
	}
	for(int i=0; i<v.size(); i++){
		pos[disj.find(i)].push_back(i);
	}
	int ans = 1;
	for(int i=0; i<v.size(); i++){
		if(pos[i].size()){
			vector<tuple<int, int, int>> tp;
			for(auto &j : pos[i]){
				int x, y, z;
				tie(x, y, z) = v[j];
				for(int dx=-1; dx<=1; dx++){
					for(int dy=-1; dy<=1; dy++){
						for(int dz=-1; dz<=1; dz++){
							auto p = make_tuple(x + dx, y + dy, z + dz);
							if(!binary_search(v.begin(), v.end(), p) && ok(get<0>(p), get<1>(p), get<2>(p))){
								tp.push_back(p);
							}
						}
					}
				}
			}
			sort(tp.begin(), tp.end());
			tp.resize(unique(tp.begin(), tp.end()) - tp.begin());
			ans += getcmp(tp) - 1;
		}
	}
	cout << ans << endl;
    return 0;
}
accuracy: 1
time_ms: 120
memory_kb: 36060
final_rank: 4

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

struct cell {
	int x, y, z;
	bool operator<(const cell& c) const {
		return x != c.x ? x < c.x : y != c.y ? y < c.y : z < c.z;
	}
	bool operator==(const cell& c) const {
		return x == c.x && y == c.y && z == c.z;
	}
	void twirl() {
		int t = x;
		x = y;
		y = z;
		z = t;
	}
};

int main() {
	// step #1. input
	int A, B, C, N;
	cin >> A >> B >> C >> N;
	vector<cell> P(N);
	for (int i = 0; i < N; i++) {
		cin >> P[i].x >> P[i].y >> P[i].z;
	}

	// step #2. enumerate all "cells to be considered"
	sort(P.begin(), P.end());
	auto fix = [&](const cell& c) -> cell {
		return cell({max(min(c.x, A - 1), 0), max(min(c.y, B - 1), 0), max(min(c.z, C - 1), 0)});
	};
	int cnt = 0;
	vector<cell> V(N * 54);
	auto push = [&](const cell& c) -> void {
		if (!binary_search(P.begin(), P.end(), c)) {
			V[cnt++] = c;
		}
	};
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < 27; j++) {
			int a = j / 9, b = j / 3 % 3, c = j % 3;
			push(fix(cell{P[i].x + (a - 1), P[i].y + (b - 1), P[i].z + (c - 1)}));
			push(cell{a == 1 ? P[i].x : a == 0 ? 0 : A - 1, b == 1 ? P[i].y : b == 0 ? 0 : B - 1, c == 1 ? P[i].z : c == 0 ? 0 : C - 1});
		}
	}
	V.resize(cnt);
	sort(V.begin(), V.end());
	V.erase(unique(V.begin(), V.end()), V.end());

	// step #3. create graph to check connectivity
	int M = V.size();
	vector<vector<int> > G(M);
	vector<pair<cell, int> > D(N + M);
	for (int i = 0; i < N + M; i++) {
		if (i < N) {
			D[i] = make_pair(P[i], -1);
		}
		else {
			D[i] = make_pair(V[i - N], i - N);
		}
	}
	for (int i = 0; i < 3; i++) {
		sort(D.begin(), D.end());
		for (int j = 1; j < N + M; j++) {
			if (D[j - 1].first.x == D[j].first.x && D[j - 1].first.y == D[j].first.y && D[j - 1].second != -1 && D[j].second != -1) {
				G[D[j - 1].second].push_back(D[j].second);
				G[D[j].second].push_back(D[j - 1].second);
			}
		}
		for (int j = 0; j < N + M; j++) {
			D[j].first.twirl();
		}
	}

	// step #4. count connected components
	int ans = 0;
	vector<bool> vis(M, false);
	for (int i = 0; i < M; i++) {
		if (!vis[i]) {
			vector<int> st = { i };
			vis[i] = true;
			while (!st.empty()) {
				int u = st.back();
				st.pop_back();
				for (int j : G[u]) {
					if (!vis[j]) {
						vis[j] = true;
						st.push_back(j);
					}
				}
			}
			ans += 1;
		}
	}
	if (N == 0) {
		ans = 1;
	}

	// step #5. output
	cout << ans << endl;

	return 0;
}
accuracy: 1
time_ms: 430
memory_kb: 88084
final_rank: 5

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

struct cell {
	int x, y, z;
	bool operator<(const cell& c) const {
		return x != c.x ? x < c.x : y != c.y ? y < c.y : z < c.z;
	}
	bool operator==(const cell& c) const {
		return x == c.x && y == c.y && z == c.z;
	}
	void twirl() {
		int t = x;
		x = y;
		y = z;
		z = t;
	}
};

int main() {
	// step #1. input
	int A, B, C, N;
	cin >> A >> B >> C >> N;
	vector<cell> P(N);
	for (int i = 0; i < N; i++) {
		cin >> P[i].x >> P[i].y >> P[i].z;
	}

	// step #2. enumerate all "cells to be considered"
	sort(P.begin(), P.end());
	auto fix = [&](const cell& c) -> cell {
		return cell({max(min(c.x, A - 1), 0), max(min(c.y, B - 1), 0), max(min(c.z, C - 1), 0)});
	};
	int cnt = 0;
	vector<cell> V(N * 54);
	auto push = [&](const cell& c) -> void {
		if (!binary_search(P.begin(), P.end(), c)) {
			V[cnt++] = c;
		}
	};
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < 27; j++) {
			int a = j / 9, b = j / 3 % 3, c = j % 3;
			push(fix(cell{P[i].x + (a - 1), P[i].y + (b - 1), P[i].z + (c - 1)}));
			push(cell{a == 1 ? P[i].x : a == 0 ? 0 : A - 1, b == 1 ? P[i].y : b == 0 ? 0 : B - 1, c == 1 ? P[i].z : c == 0 ? 0 : C - 1});
		}
	}
	V.resize(cnt);
	sort(V.begin(), V.end());
	V.erase(unique(V.begin(), V.end()), V.end());

	// step #3. create graph to check connectivity
	int M = V.size();
	vector<vector<int> > G(M);
	vector<pair<cell, int> > D(N + M);
	for (int i = 0; i < N + M; i++) {
		if (i < N) {
			D[i] = make_pair(P[i], -1);
		}
		else {
			D[i] = make_pair(V[i - N], i - N);
		}
	}
	for (int i = 0; i < 3; i++) {
		sort(D.begin(), D.end());
		for (int j = 1; j < N + M; j++) {
			if (D[j - 1].first.x == D[j].first.x && D[j - 1].first.y == D[j].first.y && D[j - 1].second != -1 && D[j].second != -1) {
				G[D[j - 1].second].push_back(D[j].second);
				G[D[j].second].push_back(D[j - 1].second);
			}
		}
		for (int j = 0; j < N + M; j++) {
			D[j].first.twirl();
		}
	}

	// step #4. count connected components
	int ans = 0;
	vector<bool> vis(M, false);
	for (int i = 0; i < M; i++) {
		if (!vis[i]) {
			vector<int> st = { i };
			vis[i] = true;
			while (!st.empty()) {
				int u = st.back();
				st.pop_back();
				for (int j : G[u]) {
					if (!vis[j]) {
						vis[j] = true;
						st.push_back(j);
					}
				}
			}
			ans += 1;
		}
	}

	// step #5. output
	cout << ans << endl;

	return 0;
}
accuracy: 0.9696969696969697
time_ms: 450
memory_kb: 88080
final_rank: 12

code_snippet: #pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<unordered_set>
#include<utility>
#include<cassert>
#include<complex>
#include<numeric>
#include<array>
#include<chrono>
using namespace std;

//#define int long long
typedef long long ll;

typedef unsigned long long ul;
typedef unsigned int ui;
constexpr ll mod = 998244353;
//constexpr ll mod = 1000000007;
const ll INF = mod * mod;
typedef pair<int, int>P;

#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
#define all(v) (v).begin(),(v).end()
typedef pair<ll, ll> LP;

template<typename T>
void chmin(T& a, T b) {
	a = min(a, b);
}
template<typename T>
void chmax(T& a, T b) {
	a = max(a, b);
}
template<typename T>
void cinarray(vector<T>& v) {
	rep(i, v.size())cin >> v[i];
}
template<typename T>
void coutarray(vector<T>& v) {
	rep(i, v.size()) {
		if (i > 0)cout << " "; cout << v[i];
	}
	cout << "\n";
}
ll mod_pow(ll x, ll n, ll m = mod) {
	if (n < 0) {
		ll res = mod_pow(x, -n, m);
		return mod_pow(res, m - 2, m);
	}
	if (abs(x) >= m)x %= m;
	if (x < 0)x += m;
	//if (x == 0)return 0;
	ll res = 1;
	while (n) {
		if (n & 1)res = res * x % m;
		x = x * x % m; n >>= 1;
	}
	return res;
}
struct modint {
	int n;
	modint() :n(0) { ; }
	modint(ll m) {
		if (m < 0 || mod <= m) {
			m %= mod; if (m < 0)m += mod;
		}
		n = m;
	}
	operator int() { return n; }
};
bool operator==(modint a, modint b) { return a.n == b.n; }
bool operator<(modint a, modint b) { return a.n < b.n; }
modint operator+=(modint& a, modint b) { a.n += b.n; if (a.n >= mod)a.n -= mod; return a; }
modint operator-=(modint& a, modint b) { a.n -= b.n; if (a.n < 0)a.n += mod; return a; }
modint operator*=(modint& a, modint b) { a.n = ((ll)a.n * b.n) % mod; return a; }
modint operator+(modint a, modint b) { return a += b; }
modint operator-(modint a, modint b) { return a -= b; }
modint operator*(modint a, modint b) { return a *= b; }
modint operator^(modint a, ll n) {
	if (n == 0)return modint(1);
	modint res = (a * a) ^ (n / 2);
	if (n % 2)res = res * a;
	return res;
}

ll inv(ll a, ll p) {
	return (a == 1 ? 1 : (1 - p * inv(p % a, a)) / a + p);
}
modint operator/(modint a, modint b) { return a * modint(inv(b, mod)); }
modint operator/=(modint& a, modint b) { a = a / b; return a; }
const int max_n = 1 << 20;
modint fact[max_n], factinv[max_n];
void init_f() {
	fact[0] = modint(1);
	for (int i = 0; i < max_n - 1; i++) {
		fact[i + 1] = fact[i] * modint(i + 1);
	}
	factinv[max_n - 1] = modint(1) / fact[max_n - 1];
	for (int i = max_n - 2; i >= 0; i--) {
		factinv[i] = factinv[i + 1] * modint(i + 1);
	}
}
modint comb(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[b] * factinv[a - b];
}
modint combP(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[a - b];
}

ll gcd(ll a, ll b) {
	a = abs(a); b = abs(b);
	if (a < b)swap(a, b);
	while (b) {
		ll r = a % b; a = b; b = r;
	}
	return a;
}
typedef long double ld;
typedef pair<ld, ld> LDP;
const ld eps = 1e-8;
const ld pi = acosl(-1.0);
template<typename T>
void addv(vector<T>& v, int loc, T val) {
	if (loc >= v.size())v.resize(loc + 1, 0);
	v[loc] += val;
}
/*const int mn = 100005;
bool isp[mn];
vector<int> ps;
void init() {
	fill(isp + 2, isp + mn, true);
	for (int i = 2; i < mn; i++) {
		if (!isp[i])continue;
		ps.push_back(i);
		for (int j = 2 * i; j < mn; j += i) {
			isp[j] = false;
		}
	}
}*/

//[,val)
template<typename T>
auto prev_itr(set<T>& st, T val) {
	auto res = st.lower_bound(val);
	if (res == st.begin())return st.end();
	res--; return res;
}

//[val,)
template<typename T>
auto next_itr(set<T>& st, T val) {
	auto res = st.lower_bound(val);
	return res;
}
using mP = pair<modint, modint>;


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

struct uf {
private:
	vector<int> par, ran;
public:
	uf(int n) {
		par.resize(n, 0);
		ran.resize(n, 0);
		rep(i, n) {
			par[i] = i;
		}
	}
	int find(int x) {
		if (par[x] == x)return x;
		else return par[x] = find(par[x]);
	}
	void unite(int x, int y) {
		x = find(x), y = find(y);
		if (x == y)return;
		if (ran[x] < ran[y]) {
			par[x] = y;
		}
		else {
			par[y] = x;
			if (ran[x] == ran[y])ran[x]++;
		}
	}
	bool same(int x, int y) {
		return find(x) == find(y);
	}
};
void solve() {
	int a, b, c, n; cin >> a >> b >> c >> n;
	vector<vector<P>> vz(c);
	vector<vector<P>> vx(c);
	using ar = array<int, 3>;
	vector<vector<vector<ar>>> vy(c);
	rep(i, n) {
		int x, y, z; cin >> x >> y >> z;
		vz[z].push_back({ x,y });
	}
	int tmp = 0;
	rep(i, c) {
		if (vz[i].empty()) {
			vx[i] = { { 0,a } };
			vy[i].push_back({ {{0,b,tmp}} });
			tmp++;
			continue;
		}
		sort(all(vz[i]));
		int le = 0;
		rep(j, vz[i].size()) {
			if (le < vz[i][j].first) {
				vx[i].push_back({ le,vz[i][j].first });
				vy[i].push_back({ {0,b,tmp} });tmp++;
			}
			vx[i].push_back({ vz[i][j].first,vz[i][j].first + 1 });
			le = vz[i][j].first + 1;
			int l = j;
			while (j + 1 < vz[i].size() && vz[i][j].first == vz[i][j + 1].first) {
				j++;
			}
			int loc = vy[i].size();
			vy[i].push_back({});
			int ly = 0;
			Rep1(k, l, j) {
				int cy = vz[i][k].second;
				if (ly < cy) {
					vy[i][loc].push_back({ ly,cy,tmp }); tmp++;
				}
				ly = cy + 1;
			}
			if (ly < b) {
				vy[i][loc].push_back({ ly,b,tmp }); tmp++;
			}
		}
		if (le < a) {
			vx[i].push_back({ le,a });
			vy[i].push_back({ {0,b,tmp} }); tmp++;
		}
	}
	uf u(tmp);
	vector<bool> exi(tmp);
	//same z
	rep(i, c) {
		rep(j, vx[i].size() - 1) {
			vector<ar>& lv = vy[i][j];
			vector<ar>& rv = vy[i][j + 1];
			int idl = 0, idr = 0;
			while (idl < lv.size() && idr < rv.size()) {
				int le = max(lv[idl][0], rv[idr][0]);
				int ri = min(lv[idl][1], rv[idr][1]);
				if (le < ri) {
					u.unite(lv[idl][2], rv[idr][2]);
				}
				if (lv[idl][1] < rv[idr][1]) {
					idl++;
				}
				else idr++;
			}
		}
	}
	//another z
	rep(i, c - 1) {
		int id1 = 0, id2 = 0;
		while (id1 < vx[i].size() && id2 < vx[i+1].size()) {
			int lx = max(vx[i][id1].first, vx[i + 1][id2].first);
			int rx = min(vx[i][id1].second, vx[i + 1][id2].second);
			if (lx < rx) {
				vector<ar>& lv = vy[i][id1];
				vector<ar>& rv = vy[i + 1][id2];
				int idl = 0, idr = 0;
				while (idl < lv.size() && idr < rv.size()) {
					int le = max(lv[idl][0], rv[idr][0]);
					int ri = min(lv[idl][1], rv[idr][1]);
					if (le < ri) {
						u.unite(lv[idl][2], rv[idr][2]);
					}
					if (lv[idl][1] < rv[idr][1]) {
						idl++;
					}
					else idr++;
				}
			}
			if (vx[i][id1].second < vx[i + 1][id2].second) {
				id1++;
			}
			else {
				id2++;
			}
		}
	}
	rep(i, tmp)exi[u.find(i)] = true;
	int ans = 0; rep(i, tmp)if (exi[i])ans++;
	cout << ans << "\n";
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout << fixed << setprecision(10);
	//init_f();
	//init();
	//while(true)
	//expr();
	//int t; cin >> t; rep(i, t)
	solve();
	return 0;
}
accuracy: 1
time_ms: 130
memory_kb: 172880
final_rank: 6

code_snippet: #include <bits/stdc++.h>
using namespace std;
int main(){
  int A, B, C, N;
  cin >> A >> B >> C >> N;
  vector<int> X(N), Y(N), Z(N);
  for (int i = 0; i < N; i++){
    cin >> X[i] >> Y[i] >> Z[i];
  }
  vector<int> rx;
  rx.push_back(0);
  for (int i = 0; i < N; i++){
    rx.push_back(X[i]);
    if (X[i] < A - 1){
      rx.push_back(X[i] + 1);
    }
  }
  sort(rx.begin(), rx.end());
  rx.erase(unique(rx.begin(), rx.end()), rx.end());
  int A2 = rx.size();
  rx.push_back(A);
  for (int i = 0; i < N; i++){
    X[i] = lower_bound(rx.begin(), rx.end(), X[i]) - rx.begin();
  }
  vector<vector<int>> id(A2);
  for (int i = 0; i < N; i++){
    id[X[i]].push_back(i);
  }
  int V = 0;
  vector<pair<int, int>> E;
  vector<vector<int>> ry(A2);
  vector<int> B2(A2);
  vector<vector<vector<pair<int, int>>>> upd(A2);
  vector<vector<int>> uc(A2);
  for (int i = 0; i < A2; i++){
    ry[i].push_back(0);
    int cnt = id[i].size();
    for (int j = 0; j < cnt; j++){
      ry[i].push_back(Y[id[i][j]]);
      if (Y[id[i][j]] < B - 1){
        ry[i].push_back(Y[id[i][j]] + 1);
      }
    }
    sort(ry[i].begin(), ry[i].end());
    ry[i].erase(unique(ry[i].begin(), ry[i].end()), ry[i].end());
    B2[i] = ry[i].size();
    vector<vector<int>> id2(B2[i]);
    for (int j = 0; j < cnt; j++){
      int Y2 = lower_bound(ry[i].begin(), ry[i].end(), Y[id[i][j]]) - ry[i].begin();
      id2[Y2].push_back(id[i][j]);
    }
    upd[i].resize(B2[i]);
    for (int j = 0; j < B2[i]; j++){
      int cnt2 = id2[j].size();
      for (int k = 0; k < cnt2; k++){
        upd[i][j].push_back(make_pair(Z[id2[j][k]], -1));
      }
      vector<int> rz;
      rz.push_back(-1);
      rz.push_back(C);
      for (int k = 0; k < cnt2; k++){
        rz.push_back(Z[id2[j][k]]);
      }
      sort(rz.begin(), rz.end());
      int cnt3 = rz.size();
      for (int k = 0; k < cnt3 - 1; k++){
        if (rz[k + 1] - rz[k] > 1){
          upd[i][j].push_back(make_pair(rz[k] + 1, V));
          V++;
        }
      }
    }
    uc[i].resize(B2[i]);
    for (int j = 0; j < B2[i]; j++){
      uc[i][j] = upd[i][j].size();
    }
    for (int j = 0; j < B2[i] - 1; j++){
      vector<tuple<int, int, int>> upd2;
      for (int k = 0; k < 2; k++){
        for (int l = 0; l < uc[i][j + k]; l++){
          upd2.push_back(make_tuple(upd[i][j + k][l].first, k, upd[i][j + k][l].second));
        }
      }
      sort(upd2.begin(), upd2.end());
      int cnt2 = upd2.size();
      vector<int> c = {-1, -1};
      for (int k = 0; k < cnt2; k++){
        int t = get<0>(upd2[k]);
        int h = get<1>(upd2[k]);
        int v = get<2>(upd2[k]);
        c[h] = v;
        bool ok = true;
        if (k < cnt2 - 1){
          if (get<0>(upd2[k + 1]) == t){
            ok = false;
          }
        }
        if (ok){
          if (c[0] != -1 && c[1] != -1){
            E.push_back(make_pair(c[0], c[1]));
          }
        }
      }
    }
  }
  for (int i = 0; i < A2 - 1; i++){
    vector<int> ry2;
    for (int j = i; j <= i + 1; j++){
      for (int k = 0; k < B2[j]; k++){
        ry2.push_back(ry[j][k]);
      }
    }
    sort(ry2.begin(), ry2.end());
    ry2.erase(unique(ry2.begin(), ry2.end()), ry2.end());
    int cnt = ry2.size();
    for (int j = 0; j < cnt; j++){
      vector<int> yp(2);
      for (int k = 0; k < 2; k++){
        yp[k] = upper_bound(ry[i + k].begin(), ry[i + k].end(), ry2[j]) - ry[i + k].begin() - 1;
      }
      vector<tuple<int, int, int>> upd2;
      for (int k = 0; k < 2; k++){
        for (int l = 0; l < uc[i + k][yp[k]]; l++){
          upd2.push_back(make_tuple(upd[i + k][yp[k]][l].first, k, upd[i + k][yp[k]][l].second));
        }
      }
      sort(upd2.begin(), upd2.end());
      int cnt2 = upd2.size();
      vector<int> c = {-1, -1};
      for (int k = 0; k < cnt2; k++){
        int t = get<0>(upd2[k]);
        int h = get<1>(upd2[k]);
        int v = get<2>(upd2[k]);
        c[h] = v;
        bool ok = true;
        if (k < cnt2 - 1){
          if (get<0>(upd2[k + 1]) == t){
            ok = false;
          }
        }
        if (ok){
          if (c[0] != -1 && c[1] != -1){
            E.push_back(make_pair(c[0], c[1]));
          }
        }
      }
    }
  }
  int M = E.size();
  vector<vector<int>> E2(V);
  for (int i = 0; i < M; i++){
    int v = E[i].first;
    int w = E[i].second;
    E2[v].push_back(w);
    E2[w].push_back(v);
  }
  int ans = 0;
  vector<bool> used(V, false);
  for (int i = 0; i < V; i++){
    if (!used[i]){
      used[i] = true;
      ans++;
      queue<int> Q;
      Q.push(i);
      while (!Q.empty()){
        int v = Q.front();
        Q.pop();
        for (int w : E2[v]){
          if (!used[w]){
            used[w] = true;
            Q.push(w);
          }
        }
      }
    }
  }
  cout << ans << endl;
}
accuracy: 1
time_ms: 50
memory_kb: 22872
final_rank: 1

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


#define NUM 1000005
typedef pair<int,int> P;

struct Info{
	Info(int arg_x,int arg_y,int arg_z){
		x = arg_x;
		y = arg_y;
		z = arg_z;
	}
	int x,y,z;
};

int N;
int boss[NUM],height[NUM];
int diff_x[3] = {-1,0,1},diff_y[3] = {-1,0,1},diff_z[3] = {-1,0,1};
int X,Y,Z;
int num_DEL,num_REMAIN;
vector<Info> info,DEL_GROUP[NUM];
vector<P> info_DELETE[NUM],info_REMAIN[NUM];
map<P,int> DELETE[NUM],REMAIN[NUM];


bool rangeCheck(int x,int y, int z){

	return x >= 0 && x <= X-1 && y >= 0 && y <= Y-1 && z >= 0 && z <= Z-1;
}

int get_boss(int id){
	if(boss[id] == id)return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

int is_same(int x,int y){
	return get_boss(x) == get_boss(y);
}

void unite(int x,int y){
	int boss_x = get_boss(x);
	int boss_y = get_boss(y);

	if(boss_x == boss_y)return;

	if(height[x] > height[y]){

		boss[boss_y] = boss_x;

	}else if(height[x] < height[y]){

		boss[boss_x] = boss_y;

	}else{ //height[x] == height[y]

		boss[boss_y] = boss_x;
		height[x]++;
	}
}

void init(int num){

	for(int i = 0; i < num; i++){
		boss[i] = i;
		height[i] = 0;
	}
}

bool is_DELETE(int x,int y,int z){

	auto at = DELETE[x].find(make_pair(y,z));

	if(at != DELETE[x].end()){

		return true;
	}else{

		return false;
	}
}

int main(){

	scanf("%d %d %d %d",&X,&Z,&Y,&num_DEL);

	int index_DELETE = 0;

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

		int x,z,y;

		scanf("%d %d %d",&x,&z,&y);

		DELETE[x][P(y,z)] = index_DELETE++;
		info_DELETE[x].push_back(P(y,z));
		info.push_back(Info(x,y,z));
	}

	init(index_DELETE);

	//削除するキューブを連結させる
	for(int i = 0; i < index_DELETE; i++){

		Info tmp_info = info[i];

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

					if(diff_x[a] == 0 && diff_y[b] == 0 && diff_z[c] == 0)continue;

					int adj_x = tmp_info.x+diff_x[a];
					int adj_y = tmp_info.y+diff_y[b];
					int adj_z = tmp_info.z+diff_z[c];

					if(rangeCheck(adj_x,adj_y,adj_z) == true && is_DELETE(adj_x,adj_y,adj_z) == true){

						int from = i;
						int to = DELETE[adj_x][P(adj_y,adj_z)];

						unite(from,to);
					}

				}
			}
		}
	}

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

		DEL_GROUP[get_boss(i)].push_back(Info(info[i]));
	}


	int ans = 1;

	//点連結させた、取り除くキューブ集団ごとに処理する
	for(int i = 0; i < index_DELETE; i++){

		if(DEL_GROUP[i].size() == 0)continue;

		int index_REMAIN = 0;
		int min_x = BIG_NUM,max_x = -BIG_NUM;

		for(int k = 0; k < DEL_GROUP[i].size(); k++){

			min_x = min(min_x,DEL_GROUP[i][k].x);
			max_x = max(max_x,DEL_GROUP[i][k].x);
		}

		min_x = max(0,min_x-2);
		max_x = min(X-1,max_x+2);

		for(int k = min_x; k <= max_x; k++){
			REMAIN[k].clear();
			info_REMAIN[k].clear();
		}

		int L = BIG_NUM,R = -BIG_NUM;

		for(int k = 0; k < DEL_GROUP[i].size(); k++){

			Info tmp_info = DEL_GROUP[i][k];

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

						if(diff_x[a] == 0 && diff_y[b] == 0 && diff_z[c] == 0)continue;

						int adj_x = tmp_info.x+diff_x[a];
						int adj_y = tmp_info.y+diff_y[b];
						int adj_z = tmp_info.z+diff_z[c];

						if(rangeCheck(adj_x,adj_y,adj_z) == false|| is_DELETE(adj_x,adj_y,adj_z) == true){

							continue;
						}
						auto at = REMAIN[adj_x].find(P(adj_y,adj_z));
						if(at != REMAIN[adj_x].end())continue;

						L = min(L,adj_x);
						R = max(R,adj_x);
						REMAIN[adj_x][P(adj_y,adj_z)] = index_REMAIN++;
						info_REMAIN[adj_x].push_back(P(adj_y,adj_z));
					}
				}
			}
		}

		if(index_REMAIN == 0)continue;

		init(index_REMAIN);

		//REMAINを面連結させる
		for(int x = L; x <= R;x++){

			if(info_REMAIN[x].size() == 0)continue;

			for(int loop = 0; loop < info_REMAIN[x].size(); loop++){

				P tmp = info_REMAIN[x][loop];

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

							int count_zero = 0;
							if(diff_x[a] == 0)count_zero++;
							if(diff_y[b] == 0)count_zero++;
							if(diff_z[c] == 0)count_zero++;

							if(count_zero != 2)continue;


							int adj_x = x+diff_x[a];
							int adj_y = tmp.first+diff_y[b];
							int adj_z = tmp.second+diff_z[c];

							if(rangeCheck(adj_x,adj_y,adj_z) == true){

								auto at = REMAIN[adj_x].find(P(adj_y,adj_z));
								if(at == REMAIN[adj_x].end())continue;

								int from = REMAIN[x][tmp];
								int to = REMAIN[adj_x][P(adj_y,adj_z)];

								unite(from,to);
							}
						}
					}
				}
			}
		}

		int num_group = 0;

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

			if(k == get_boss(k)){

				num_group++;
			}
		}

		ans += num_group-1;
	}

	printf("%d\n",ans);

	return 0;
}
accuracy: 1
time_ms: 210
memory_kb: 207740
final_rank: 10

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


#define NUM 1000005
typedef pair<int,int> P;

struct Info{
	Info(int arg_x,int arg_y,int arg_z){
		x = arg_x;
		y = arg_y;
		z = arg_z;
	}
	int x,y,z;
};

int N;
int boss[NUM],height[NUM];
int diff_x[3] = {-1,0,1},diff_y[3] = {-1,0,1},diff_z[3] = {-1,0,1};
int X,Y,Z;
int num_DEL,num_REMAIN;
vector<Info> info,DEL_GROUP[NUM];
vector<P> info_DELETE[NUM],info_REMAIN[NUM];
map<P,int> DELETE[NUM],REMAIN[NUM];


bool rangeCheck(int x,int y, int z){

	return x >= 0 && x <= X-1 && y >= 0 && y <= Y-1 && z >= 0 && z <= Z-1;
}

int get_boss(int id){
	if(boss[id] == id)return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

int is_same(int x,int y){
	return get_boss(x) == get_boss(y);
}

void unite(int x,int y){
	int boss_x = get_boss(x);
	int boss_y = get_boss(y);

	if(boss_x == boss_y)return;

	if(height[x] > height[y]){

		boss[boss_y] = boss_x;

	}else if(height[x] < height[y]){

		boss[boss_x] = boss_y;

	}else{ //height[x] == height[y]

		boss[boss_y] = boss_x;
		height[x]++;
	}
}

void init(int num){

	for(int i = 0; i < num; i++){
		boss[i] = i;
		height[i] = 0;
	}
}

bool is_DELETE(int x,int y,int z){

	auto at = DELETE[x].find(make_pair(y,z));

	if(at != DELETE[x].end()){

		return true;
	}else{

		return false;
	}
}

int main(){

	scanf("%d %d %d %d",&X,&Z,&Y,&num_DEL);

	int index_DELETE = 0;

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

		int x,z,y;

		scanf("%d %d %d",&x,&z,&y);

		DELETE[x][P(y,z)] = index_DELETE++;
		info_DELETE[x].push_back(P(y,z));
		info.push_back(Info(x,y,z));
	}

	init(index_DELETE);

	//削除するキューブを連結させる
	for(int i = 0; i < index_DELETE; i++){

		Info tmp_info = info[i];

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

					if(diff_x[a] == 0 && diff_y[b] == 0 && diff_z[c] == 0)continue;

					int adj_x = tmp_info.x+diff_x[a];
					int adj_y = tmp_info.y+diff_y[b];
					int adj_z = tmp_info.z+diff_z[c];

					if(rangeCheck(adj_x,adj_y,adj_z) == true && is_DELETE(adj_x,adj_y,adj_z) == true){

						int from = i;
						int to = DELETE[adj_x][P(adj_y,adj_z)];

						unite(from,to);
					}

				}
			}
		}
	}

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

		DEL_GROUP[get_boss(i)].push_back(Info(info[i]));
	}


	int ans = 1;

	//点連結させた、取り除くキューブ集団ごとに処理する
	for(int i = 0; i < index_DELETE; i++){

		if(DEL_GROUP[i].size() == 0)continue;

		int index_REMAIN = 0;
		int min_x = BIG_NUM,max_x = -BIG_NUM;

		for(int k = 0; k < DEL_GROUP[i].size(); k++){

			min_x = min(min_x,DEL_GROUP[i][k].x);
			max_x = max(max_x,DEL_GROUP[i][k].x);
		}

		min_x = max(0,min_x-1);
		max_x = min(X-1,max_x+1);

		for(int k = min_x; k <= max_x; k++){
			REMAIN[k].clear();
			info_REMAIN[k].clear();
		}

		int L = BIG_NUM,R = -BIG_NUM;

		for(int k = 0; k < DEL_GROUP[i].size(); k++){

			Info tmp_info = DEL_GROUP[i][k];

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

						if(diff_x[a] == 0 && diff_y[b] == 0 && diff_z[c] == 0)continue;

						int adj_x = tmp_info.x+diff_x[a];
						int adj_y = tmp_info.y+diff_y[b];
						int adj_z = tmp_info.z+diff_z[c];

						if(rangeCheck(adj_x,adj_y,adj_z) == false|| is_DELETE(adj_x,adj_y,adj_z) == true){

							continue;
						}
						auto at = REMAIN[adj_x].find(P(adj_y,adj_z));
						if(at != REMAIN[adj_x].end())continue;

						L = min(L,adj_x);
						R = max(R,adj_x);
						REMAIN[adj_x][P(adj_y,adj_z)] = index_REMAIN++;
						info_REMAIN[adj_x].push_back(P(adj_y,adj_z));
					}
				}
			}
		}

		if(index_REMAIN == 0)continue;

		init(index_REMAIN);

		//REMAINを面連結させる
		for(int x = L; x <= R;x++){

			if(info_REMAIN[x].size() == 0)continue;

			for(int loop = 0; loop < info_REMAIN[x].size(); loop++){

				P tmp = info_REMAIN[x][loop];

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

							int count_zero = 0;
							if(diff_x[a] == 0)count_zero++;
							if(diff_y[b] == 0)count_zero++;
							if(diff_z[c] == 0)count_zero++;

							if(count_zero != 2)continue;


							int adj_x = x+diff_x[a];
							int adj_y = tmp.first+diff_y[b];
							int adj_z = tmp.second+diff_z[c];

							if(rangeCheck(adj_x,adj_y,adj_z) == true){

								auto at = REMAIN[adj_x].find(P(adj_y,adj_z));
								if(at == REMAIN[adj_x].end())continue;

								int from = REMAIN[x][tmp];
								int to = REMAIN[adj_x][P(adj_y,adj_z)];

								unite(from,to);
							}
						}
					}
				}
			}
		}

		int num_group = 0;

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

			if(k == get_boss(k)){

				num_group++;
			}
		}

		ans += num_group-1;
	}

	printf("%d\n",ans);

	return 0;
}
accuracy: 0.045454545454545456
time_ms: 110
memory_kb: 169532
final_rank: 20

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


#define NUM 1000000

struct Info{
	Info(){
		x = y = z = 0;
	}

	Info(int arg_x,int arg_y,int arg_z){
		x = arg_x;
		y = arg_y;
		z = arg_z;
	}
	void set(int arg_x,int arg_y,int arg_z){
		x = arg_x;
		y = arg_y;
		z = arg_z;
	}

	bool operator<(const struct Info &arg) const{

		if(x != arg.x){

			return x < arg.x;

		}else if(y != arg.y){

			return y < arg.y;

		}else{

			return z < arg.z;
		}
	}
	bool operator==(const struct Info &arg) const{

		return x == arg.x && y == arg.y && z == arg.z;
	}

	int x,y,z;
};

int N;
int boss[NUM],height[NUM];
int diff_x[3] = {-1,0,1},diff_y[3] = {-1,0,1},diff_z[3] = {-1,0,1};
int X,Y,Z;
int num_DEL,num_REMAIN;
vector<int> DEL_GROUP[20000];
vector<Info> info_DELETE,info_REMAIN;
map<Info,bool> DELETE,REMAIN;


bool rangeCheck(int x,int y, int z){

	return x >= 0 && x <= X-1 && y >= 0 && y <= Y-1 && z >= 0 && z <= Z-1;
}

int get_boss(int id){
	if(boss[id] == id)return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

int is_same(int x,int y){
	return get_boss(x) == get_boss(y);
}

void unite(int x,int y){
	int boss_x = get_boss(x);
	int boss_y = get_boss(y);

	if(boss_x == boss_y)return;

	if(height[x] > height[y]){

		boss[boss_y] = boss_x;

	}else if(height[x] < height[y]){

		boss[boss_x] = boss_y;

	}else{ //height[x] == height[y]

		boss[boss_y] = boss_x;
		height[x]++;
	}
}

bool is_DELETE(int x,int y,int z){

	Info tmp_info;
	tmp_info.set(x,y,z);

	auto at = DELETE.find(tmp_info);

	if(at != DELETE.end()){

		return true;
	}else{

		return false;
	}
}

bool is_REMAIN(int x,int y,int z){

	Info tmp_info;
	tmp_info.set(x,y,z);

	auto at = REMAIN.find(tmp_info);

	if(at != REMAIN.end()){

		return true;
	}else{

		return false;
	}
}

int main(){

	scanf("%d %d %d %d",&X,&Y,&Z,&num_DEL);

	int index_DELETE = 0;

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

		Info tmp_info;

		scanf("%d %d %d",&tmp_info.x,&tmp_info.y,&tmp_info.z);

		DELETE[tmp_info] = index_DELETE++;
		info_DELETE.push_back(tmp_info);
	}

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

		boss[i] = i;
		height[i] = 0;
	}

	//取り除くキューブを点連結させて、グループに分ける
	for(int i = 0; i < num_DEL; i++){

		Info tmp_info = info_DELETE[i];

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

					if(diff_x[a] == 0 && diff_y[b] == 0 && diff_z[c] == 0)continue;

					int adj_x = tmp_info.x+diff_x[a];
					int adj_y = tmp_info.y+diff_y[b];
					int adj_z = tmp_info.z+diff_z[c];

					if(rangeCheck(adj_x,adj_y,adj_z) == true && is_DELETE(adj_x,adj_y,adj_z) == true){

						Info new_info;
						new_info.set(adj_x,adj_y,adj_z);

						unite(i,DELETE[new_info]);
					}
				}
			}
		}
	}

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

		DEL_GROUP[get_boss(i)].push_back(i);
	}

	int ans = 1;

	//点連結させた、取り除くキューブ集団ごとに処理する
	for(int i = 0; i < index_DELETE; i++){

		if(DEL_GROUP[i].size() == 0)continue;

		REMAIN.clear();
		info_REMAIN.clear();
		int index_REMAIN = 0;

		for(int k = 0; k < DEL_GROUP[i].size(); k++){

			Info tmp_info = info_DELETE[DEL_GROUP[i][k]];

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

						if(diff_x[a] == 0 && diff_y[b] == 0 && diff_z[c] == 0)continue;

						int adj_x = tmp_info.x+diff_x[a];
						int adj_y = tmp_info.y+diff_y[b];
						int adj_z = tmp_info.z+diff_z[c];

						if(rangeCheck(adj_x,adj_y,adj_z) == false|| is_DELETE(adj_x,adj_y,adj_z) == true
								|| is_REMAIN(adj_x,adj_y,adj_z) == true){

							continue;
						}

						Info new_info;
						new_info.set(adj_x,adj_y,adj_z);

						REMAIN[new_info] = index_REMAIN++;
						info_REMAIN.push_back(new_info);
					}
				}
			}
		}

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

			boss[k] = k;
			height[k] = 0;
		}

		//REMAINを面連結させる
		for(int k = 0; k < index_REMAIN; k++){

			Info tmp_info = info_REMAIN[k];

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

						int count_zero = 0;
						if(diff_x[a] == 0)count_zero++;
						if(diff_y[b] == 0)count_zero++;
						if(diff_z[c] == 0)count_zero++;

						if(count_zero != 2)continue;


						int adj_x = tmp_info.x+diff_x[a];
						int adj_y = tmp_info.y+diff_y[b];
						int adj_z = tmp_info.z+diff_z[c];

						if(rangeCheck(adj_x,adj_y,adj_z) == true && is_REMAIN(adj_x,adj_y,adj_z) == true){

							Info adj_info;
							adj_info.set(adj_x,adj_y,adj_z);

							int adj_index = REMAIN[adj_info];

							unite(k,adj_index);
						}
					}
				}
			}
		}

		int num_group = 0;

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

			if(k == get_boss(k)){

				num_group++;
			}
		}

		ans += num_group-1;
	}

	printf("%d\n",ans);

	return 0;
}
accuracy: 0.07575757575757576
time_ms: 100
memory_kb: 9488
final_rank: 16

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


#define NUM 1000000

struct Info{
	Info(){
		x = y = z = 0;
	}

	Info(int arg_x,int arg_y,int arg_z){
		x = arg_x;
		y = arg_y;
		z = arg_z;
	}
	void set(int arg_x,int arg_y,int arg_z){
		x = arg_x;
		y = arg_y;
		z = arg_z;
	}

	bool operator<(const struct Info &arg) const{

		if(x != arg.x){

			return x < arg.x;

		}else if(y != arg.y){

			return y < arg.y;

		}else{

			return z < arg.z;
		}
	}
	bool operator==(const struct Info &arg) const{

		return x == arg.x && y == arg.y && z == arg.z;
	}

	int x,y,z;
};

int N;
int boss[NUM],height[NUM];
int diff_x[3] = {-1,0,1},diff_y[3] = {-1,0,1},diff_z[3] = {-1,0,1};
int X,Y,Z;
int num_DEL,num_REMAIN;
vector<int> DEL_GROUP[20000];
vector<Info> info_DELETE,info_REMAIN;
map<Info,bool> DELETE,REMAIN;


bool rangeCheck(int x,int y, int z){

	return x >= 0 && x <= X-1 && y >= 0 && y <= Y-1 && z >= 0 && z <= Z-1;
}

int get_boss(int id){
	if(boss[id] == id)return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

int is_same(int x,int y){
	return get_boss(x) == get_boss(y);
}

void unite(int x,int y){
	int boss_x = get_boss(x);
	int boss_y = get_boss(y);

	if(boss_x == boss_y)return;

	if(height[x] > height[y]){

		boss[boss_y] = boss_x;

	}else if(height[x] < height[y]){

		boss[boss_x] = boss_y;

	}else{ //height[x] == height[y]

		boss[boss_y] = boss_x;
		height[x]++;
	}
}

bool is_DELETE(int x,int y,int z){

	Info tmp_info;
	tmp_info.set(x,y,z);

	auto at = DELETE.find(tmp_info);

	if(at != DELETE.end()){

		return true;
	}else{

		return false;
	}
}

bool is_REMAIN(int x,int y,int z){

	Info tmp_info;
	tmp_info.set(x,y,z);

	auto at = REMAIN.find(tmp_info);

	if(at != REMAIN.end()){

		return true;
	}else{

		return false;
	}
}

int main(){

	scanf("%d %d %d %d",&X,&Y,&Z,&num_DEL);

	int index_DELETE = 0;

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

		Info tmp_info;

		scanf("%d %d %d",&tmp_info.x,&tmp_info.y,&tmp_info.z);

		DELETE[tmp_info] = index_DELETE++;
		info_DELETE.push_back(tmp_info);
	}

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

		boss[i] = i;
		height[i] = 0;
	}

	//取り除くキューブを点連結させて、グループに分ける
	for(int i = 0; i < num_DEL; i++){

		Info tmp_info = info_DELETE[i];

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

					int adj_x = tmp_info.x+diff_x[a];
					int adj_y = tmp_info.y+diff_y[b];
					int adj_z = tmp_info.z+diff_z[c];

					if(rangeCheck(adj_x,adj_y,adj_z) == true && is_DELETE(adj_x,adj_y,adj_z) == true){

						Info new_info;
						new_info.set(adj_x,adj_y,adj_z);

						unite(i,DELETE[new_info]);
					}
				}
			}
		}
	}

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

		DEL_GROUP[get_boss(i)].push_back(i);
	}

	int ans = 1;

	//点連結させた、取り除くキューブ集団ごとに処理する
	for(int i = 0; i < index_DELETE; i++){

		if(DEL_GROUP[i].size() == 0)continue;

		REMAIN.clear();
		info_REMAIN.clear();
		int index_REMAIN = 0;

		for(int k = 0; k < DEL_GROUP[i].size(); k++){

			Info tmp_info = info_DELETE[DEL_GROUP[i][k]];

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

						int adj_x = tmp_info.x+diff_x[a];
						int adj_y = tmp_info.y+diff_y[b];
						int adj_z = tmp_info.z+diff_z[c];

						if(rangeCheck(adj_x,adj_y,adj_z) == false|| is_DELETE(adj_x,adj_y,adj_z) == true
								|| is_REMAIN(adj_x,adj_y,adj_z) == true){

							continue;
						}

						Info new_info;
						new_info.set(adj_x,adj_y,adj_z);

						REMAIN[new_info] = index_REMAIN++;
						info_REMAIN.push_back(new_info);
					}
				}
			}
		}

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

			boss[k] = k;
			height[k] = 0;
		}

		//REMAINを面連結させる
		for(int k = 0; k < index_REMAIN; k++){

			Info tmp_info = info_REMAIN[k];

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

						int count_zero = 0;
						if(diff_x[a] == 0)count_zero++;
						if(diff_y[b] == 0)count_zero++;
						if(diff_z[c] == 0)count_zero++;

						if(count_zero != 2)continue;


						int adj_x = tmp_info.x+diff_x[a];
						int adj_y = tmp_info.y+diff_y[b];
						int adj_z = tmp_info.z+diff_z[c];

						if(rangeCheck(adj_x,adj_y,adj_z) == true && is_REMAIN(adj_x,adj_y,adj_z) == true){

							Info adj_info;
							adj_info.set(adj_x,adj_y,adj_z);

							int adj_index = REMAIN[adj_info];

							unite(k,adj_index);
						}
					}
				}
			}
		}

		int num_group = 0;

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

			if(k == get_boss(k)){

				num_group++;
			}
		}

		ans += num_group-1;
	}

	printf("%d\n",ans);

	return 0;
}
accuracy: 0.07575757575757576
time_ms: 160
memory_kb: 14492
final_rank: 18

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


#define NUM 1000000

struct Info{
	Info(){
		x = y = z = 0;
	}

	Info(int arg_x,int arg_y,int arg_z){
		x = arg_x;
		y = arg_y;
		z = arg_z;
	}
	void set(int arg_x,int arg_y,int arg_z){
		x = arg_x;
		y = arg_y;
		z = arg_z;
	}

	bool operator<(const struct Info &arg) const{

		if(x != arg.x){

			return x < arg.x;

		}else if(y != arg.y){

			return y < arg.y;

		}else{

			return z < arg.z;
		}
	}
	bool operator==(const struct Info &arg) const{

		return x == arg.x && y == arg.y && z == arg.z;
	}

	int x,y,z;
};

int N;
int boss[NUM],height[NUM];
int diff_x[3] = {-1,0,1},diff_y[3] = {-1,0,1},diff_z[3] = {-1,0,1};
int X,Y,Z;
int num_DEL,num_REMAIN;
vector<Info> info_DELETE,info_REMAIN;
map<Info,bool> DELETE,REMAIN;


bool rangeCheck(int x,int y, int z){

	return x >= 0 && x <= X-1 && y >= 0 && y <= Y-1 && z >= 0 && z <= Z-1;
}

int get_boss(int id){
	if(boss[id] == id)return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

int is_same(int x,int y){
	return get_boss(x) == get_boss(y);
}

void unite(int x,int y){
	int boss_x = get_boss(x);
	int boss_y = get_boss(y);

	if(boss_x == boss_y)return;

	if(height[x] > height[y]){

		boss[boss_y] = boss_x;

	}else if(height[x] < height[y]){

		boss[boss_x] = boss_y;

	}else{ //height[x] == height[y]

		boss[boss_y] = boss_x;
		height[x]++;
	}
}

bool is_DELETE(int x,int y,int z){

	Info tmp_info;
	tmp_info.set(x,y,z);

	auto at = DELETE.find(tmp_info);

	if(at != DELETE.end()){

		return true;
	}else{

		return false;
	}
}

bool is_REMAIN(int x,int y,int z){

	Info tmp_info;
	tmp_info.set(x,y,z);

	auto at = REMAIN.find(tmp_info);

	if(at != REMAIN.end()){

		return true;
	}else{

		return false;
	}
}

int main(){

	scanf("%d %d %d %d",&X,&Y,&Z,&num_DEL);

	int index_DELETE = 0;

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

		Info tmp_info;

		scanf("%d %d %d",&tmp_info.x,&tmp_info.y,&tmp_info.z);

		DELETE[tmp_info] = index_DELETE++;
		info_DELETE.push_back(tmp_info);
	}

	int index_REMAIN = 0;

	//取り除くキューブに点で接する、取り除かれないキューブを調べる
	for(int i = 0; i < num_DEL; i++){

		Info tmp_info = info_DELETE[i];

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

					int adj_x = tmp_info.x+diff_x[a];
					int adj_y = tmp_info.y+diff_y[b];
					int adj_z = tmp_info.z+diff_z[c];

					if(rangeCheck(adj_x,adj_y,adj_z) == false || is_DELETE(adj_x,adj_y,adj_z) == true
							|| is_REMAIN(adj_x,adj_y,adj_z) == true)continue;

					Info new_info;
					new_info.set(adj_x,adj_y,adj_z);

					REMAIN[new_info] = index_REMAIN++;
					info_REMAIN.push_back(new_info);
				}
			}
		}
	}

	//取り除かれないキューブを、面連結でuniteする
	for(int i = 0; i < index_REMAIN; i++){

		boss[i] = i;
		height[i] = 0;
	}

	int count_zero;

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

		Info tmp_info = info_REMAIN[i];

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

					count_zero = 0;
					if(diff_x[a] == 0)count_zero++;
					if(diff_y[b] == 0)count_zero++;
					if(diff_z[c] == 0)count_zero++;

					if(count_zero != 2)continue;


					int adj_x = tmp_info.x+diff_x[a];
					int adj_y = tmp_info.y+diff_y[b];
					int adj_z = tmp_info.z+diff_z[c];

					if(rangeCheck(adj_x,adj_y,adj_z) == true && is_REMAIN(adj_x,adj_y,adj_z) == true){

						Info adj_info;
						adj_info.set(adj_x,adj_y,adj_z);

						int adj_index = REMAIN[adj_info];

						unite(i,adj_index);
					}
				}
			}
		}
	}

	int ans = 0;

	//取り除かれないキューブのグループ数を数える
	for(int i = 0; i < index_REMAIN; i++){

		if(get_boss(i) == i){

			ans++;
		}
	}

	printf("%d\n",ans);

	return 0;
}
accuracy: 0.07575757575757576
time_ms: 140
memory_kb: 14560
final_rank: 17

code_snippet: #include<bits/stdc++.h>
using namespace std;
 
int A,B,C,N;
const int MAX = 20000*30;
int d[MAX];
void init(){ memset( d, -1, sizeof( d ) ); }
int find(int a){ return d[a]<0?a:(d[a]=find(d[a])); }
bool merge(int a, int b){
  a = find(a); b = find(b);
  if( a == b ) return false;
  if( d[a] > d[b] ) swap( a, b );
  d[a] += d[b]; d[b] = a;
  return true;
}
bool same(int a,int b){
  return find(a) == find(b);
}
 
struct P3{
  int x,y,z;
  P3(){}
  P3(int x,int y,int z) : x(x),y(y),z(z) {}
  bool operator<(const P3& p) const {
    if( x == p.x )
      if( y == p.y )
        return z < p.z;
      else
        return y < p.y;
    else
      return x< p.x;
  }
};
 
int dx[]={ 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,-1,-1,-1,-1,-1,-1,-1,-1};
int dy[]={ 1, 1, 1, 0, 0, 0, 1,-1,-1, 1, 1, 1, 0, 0, 0,-1,-1,-1, 1, 1, 1, 0, 0, 0,-1,-1,-1};
int dz[]={ 1, 0,-1, 1, 0,-1, 1, 0,-1, 1, 0,-1, 0, 1,-1, 1, 0,-1, 1, 0,-1, 1, 0,-1, 1, 0,-1};
int mx[]={ 1,-1, 0, 0, 0, 0};
int my[]={ 0, 0, 1,-1, 0, 0};
int mz[]={ 0, 0, 0, 0, 1,-1};
map<P3,int> id;
set<P3> umes;
map<int,set<int>> divi;
int cnt;
bool used[MAX];
bool ume[MAX];
 
bool outer(int x,int y, int z ){
  if( x < 0 || x >= A || y < 0 || y >= B || z < 0 || z >= C ) return true;
  return false;
}
 
bool check( int x,int y,int z, bool f = false ){
  if( id.count( P3( x, y, z ) ) == 0 ) return false;
  int v = id[ P3(x,y,z) ];
  if( used[ v ] ) return false;
  if( f && !ume[ v ] ) return false;
  if( !f && ume[ v ] ) return false;
  return true;
}
 
void bfs(int x,int y,int z, bool f = false ){
  int v = id[P3(x,y,z)];
  if( used[v] ) return;
  queue<P3> q;
  q.push( P3(x,y,z) );
  used[ v ] = true;
  while( !q.empty() ){
    P3 p = q.front(); q.pop();
    x = p.x; y = p.y; z = p.z;
    v = id[ p ];
    int n = 6;
    if( f ) n = 27;
    for(int i=0;i<n;i++){
      int nx = x + dx[i], ny = y + dy[i], nz = z + dz[i];
      if(!f) nx = x + mx[i], ny = y + my[i], nz = z + mz[i];
      if( check( nx, ny, nz, f ) ) {
        int nv = id[ P3(nx,ny,nz) ];
        merge( v, nv );
        q.push( P3(nx,ny,nz) );
        used[ nv ] = true;
      }
    }
  }
}
 
int main(){
  cin >> A >> B >> C >> N;
  init();
  for(int i=0;i<N;i++){
    int x,y,z; cin >> x >> y >> z;
    for(int j=0;j<27;j++){
      int nx = x + dx[j], ny = y + dy[j], nz = z + dz[j];
      if( outer( nx, ny, nz ) ) continue;
      if( !id.count( P3( nx,ny,nz) ) ) 
        id[ P3(nx,ny,nz) ] = cnt++;     
    }
    umes.insert( P3(x,y,z) );
    ume[id[P3(x,y,z)]] = true;
  }
   
  for( auto it = id.begin(); it != id.end(); it++ ){
    P3 np = it->first;
    int v = it->second;
    if( ume[v] ) 
      bfs( np.x, np.y, np.z, true );
    else
      bfs( np.x, np.y, np.z );
  }
 
  for( auto it = umes.begin(); it != umes.end(); it++ ){
    P3 p = *it;
    int v = find( id[p] );
    for(int i=0;i<27;i++){
      int nx = p.x + dx[i], ny = p.y + dy[i], nz = p.z + dz[i];
      if( id.count( P3(nx,ny,nz) ) == 0 ) continue;
      if( umes.count( P3( nx, ny, nz ) ) ) continue;
      divi[ v ].insert( find( id[ P3(nx,ny,nz) ] ) );
    }
  }
 
  int res = 1;
  for( auto it = divi.begin(); it != divi.end(); it++ ){
    res += it->second.size()-1;
  }
  cout << res << endl;
   
}
accuracy: 1
time_ms: 850
memory_kb: 43024
final_rank: 9

code_snippet: #include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <cassert>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
const ll mod=1000000007;
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
// head

struct point {
	int x,y,z;
	point() {}
	point(int x,int y,int z):x(x),y(y),z(z){}
};
vector<point> vs;
int a,b,c,n,x,y,z;
map<point,int> pt,del;
bool operator < (const point &a,const point &b) {
	return a.x<b.x||(a.x==b.x&&a.y<b.y)||(a.x==b.x&&a.y==b.y&&a.z<b.z);
}
bool valid(point p) {
	return p.x>=0&&p.x<a&&p.y>=0&&p.y<b&&p.z>=0&&p.z<c;
}
void dfs(point p) {
	vs.pb(p); del[p]=1;
	rep(dx,-1,2) rep(dy,-1,2) rep(dz,-1,2) {
		point q(p.x+dx,p.y+dy,p.z+dz);
		if (del.count(q)&&del[q]==0) dfs(q);
		if (valid(q)&&!del.count(q)) pt[q]=0;
	}
}
void dfs2(point p) {
	pt[p]=1;
	rep(dx,-1,2) rep(dy,-1,2) rep(dz,-1,2) if (abs(dx)+abs(dy)+abs(dz)==1) {
		point q(p.x+dx,p.y+dy,p.z+dz);
		if (pt.count(q)&&pt[q]==0) dfs2(q);
	}
}

int main() {
	scanf("%d%d%d%d",&a,&b,&c,&n);
	rep(i,0,n) {
		scanf("%d%d%d",&x,&y,&z);
		del[point(x,y,z)]=0;
	}
	vector<point> d;
	for (auto p:del) d.pb(p.fi);
	int ret=1;
	for (auto p:d) if (del[p]==0) {
		pt.clear();
		dfs(p);
		ret--;
		vector<point> vs;
		for (auto q:pt) vs.pb(q.fi);
		for (auto q:vs) if (pt[q]==0) {
			dfs2(q);
			ret++;
		}
	}
	printf("%d\n",ret);
}
accuracy: 1
time_ms: 190
memory_kb: 8048
final_rank: 2

code_snippet: #include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <cassert>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
const ll mod=1000000007;
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
// head

struct point {
	int x,y,z;
	point() {}
	point(int x,int y,int z):x(x),y(y),z(z){}
};
vector<point> vs;
int a,b,c,n,x,y,z;
map<point,int> pt;
set<point> del;
bool operator < (const point &a,const point &b) {
	return a.x<b.x||(a.x==b.x&&a.y<b.y)||(a.x==b.x&&a.y==b.y&&a.z<b.z);
}
bool valid(point p) {
	return p.x>=0&&p.x<a&&p.y>=0&&p.y<b&&p.z>=0&&p.z<c;
}
void dfs(point p) {
	vs.pb(p); pt[p]=1;
	rep(dx,-1,2) rep(dy,-1,2) rep(dz,-1,2) {
		point q(p.x+dx,p.y+dy,p.z+dz);
		if (pt.count(q)&&pt[q]==0) dfs(q);
	}
}
void dfs2(point p) {
	pt[p]=2;
	rep(dx,-1,2) rep(dy,-1,2) rep(dz,-1,2) if (abs(dx)+abs(dy)+abs(dz)==1) {
		point q(p.x+dx,p.y+dy,p.z+dz);
		if (pt.count(q)&&pt[q]==1) dfs2(q);
	}
}

int main() {
	scanf("%d%d%d%d",&a,&b,&c,&n);
	rep(i,0,n) {
		scanf("%d%d%d",&x,&y,&z);
		del.insert(point(x,y,z));
		rep(dx,-1,2) rep(dy,-1,2) rep(dz,-1,2) {
			point p(x+dx,y+dy,z+dz);
			if (valid(p)) pt[p]=0;
		}
	}
	for (auto p:del) pt.erase(p);
	vector<point> d;
	for (auto p:pt) d.pb(p.fi);
	int ret=1;
	for (auto p:d) if (pt[p]==0) {
		vs.clear();
		dfs(p);
		ret--;
		for (auto q:vs) if (pt[q]==1) {
			dfs2(p);
			ret++;
		}
	}
	printf("%d\n",ret);
}
accuracy: 0.06060606060606061
time_ms: 390
memory_kb: 25688
final_rank: 19

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> P;
typedef pair<int, P > PP;
#define MAX 10000000
int cc=1;
int A,B,C,N;
set< PP > s;
vector< PP > t;
   
map< P , set< P > > xy,yz,zx;
   
int par[MAX],rak[MAX];
   
void init(){
  for(int i=0;i<MAX;i++)
    par[i]=i,rak[i]=1;
}
   
int find(int x){
  if(par[x]==x)return x;
  return par[x]=find(par[x]);
}
   
void unite(int x,int y){
  x=find(x),y=find(y);
  if(x==y)return;
  if(rak[x]<rak[y])swap(x,y);
  par[y]=x;
  rak[x]+=rak[y];
}
   
void calc(map< P , set<P> > &mp){
  map< P , set<P> > :: iterator it;
  for(it=mp.begin();it!=mp.end();it++){
    set<P> :: iterator si=it->second.begin();
    set<P> :: iterator ti=it->second.end();
    set<P> :: iterator A=si,B;
    while(1){
      B=A;
      B++;
      if(B==ti)break;
      if(A->second>0&&B->second>0){
        unite(A->second,B->second);
      }
      A=B;
    }
  }
}
   
void add(int nx,int ny,int nz){
  if(nx<0||A<=nx||ny<0||B<=ny||nz<0||C<=nz)return;
  if(s.count(PP(nx,P(ny,nz))))return;
  s.insert( PP(nx,P(ny,nz)) );
  xy[ P(nx,ny) ].insert( P(nz,cc) );
  yz[ P(ny,nz) ].insert( P(nx,cc) );
  zx[ P(nz,nx) ].insert( P(ny,cc) );     
  cc++;
}
   
int main(){
  init();
  scanf("%d %d %d %d",&A,&B,&C,&N);
  t.resize(N);
  
  for(int i=0;i<N;i++){
    int x,y,z;
    scanf("%d %d %d",&x,&y,&z);
    s.insert( PP(x,P(y,z)) );
    t[i]=PP(x,P(y,z));
  
    xy[ P(x,y) ].insert( P(z,0) );
    yz[ P(y,z) ].insert( P(x,0) );
    zx[ P(z,x) ].insert( P(y,0) );     
  }
  
  
  add(0,0,0);
  
   
  for(int i=0;i<(int)t.size();i++){
    int x=t[i].first;
    int y=t[i].second.first;
    int z=t[i].second.second;
       
    for(int dx=-1;dx<=1;dx++){
      for(int dy=-1;dy<=1;dy++){
        for(int dz=-1;dz<=1;dz++){
          add(x+dx,y+dy,z+dz);
   
          add(x+dx,0,0);
          add(0,y+dy,0);
          add(0,0,z+dz);
   
          //          add(x+dx,B-1,C-1);
          //          add(A-1,y+dy,C-1);
          //          add(A-1,B-1,z+dz);
   
          //          add(x+dx,B-1,0);
          //          add(A-1,y+dy,0);
          //          add(A-1,0,z+dz);
   
          //          add(x+dx,0,C-1);
          //          add(0,y+dy,C-1);
          //          add(0,B-1,z+dz);
   
          add(x+dx,y+dy,0);
          add(0,y+dy,z+dz);
          add(x+dx,0,z+dz);
   
          //          add(x+dx,y+dy,C-1);
          //          add(A-1,y+dy,z+dz);
          //          add(x+dx,B-1,z+dz);
        }
      }
    }
  }
     
   
  calc(xy);
  calc(yz);
  calc(zx);
   
  int ans=0;
  for(int i=1;i<cc;i++)
    if(find(i)==i)ans++;
   
  printf("%d\n",ans);
  return 0;
}
accuracy: 1
time_ms: 1780
memory_kb: 416708
final_rank: 11

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

int A,B,C,N;
const int MAX = 20000*30;
int d[MAX];
void init(){ memset( d, -1, sizeof( d ) ); }
int find(int a){ return d[a]<0?a:(d[a]=find(d[a])); }
bool merge(int a, int b){
  a = find(a); b = find(b);
  if( a == b ) return false;
  if( d[a] > d[b] ) swap( a, b );
  d[a] += d[b]; d[b] = a;
  return true;
}
bool same(int a,int b){
  return find(a) == find(b);
}

struct P3{
  int x,y,z;
  P3(){}
  P3(int x,int y,int z) : x(x),y(y),z(z) {}
  bool operator<(const P3& p) const {
    if( x == p.x )
      if( y == p.y )
        return z < p.z;
      else
        return y < p.y;
    else
      return x< p.x;
  }
};

int dx[]={ 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,-1,-1,-1,-1,-1,-1,-1,-1};
int dy[]={ 1, 1, 1, 0, 0, 0, 1,-1,-1, 1, 1, 1, 0, 0, 0,-1,-1,-1, 1, 1, 1, 0, 0, 0,-1,-1,-1};
int dz[]={ 1, 0,-1, 1, 0,-1, 1, 0,-1, 1, 0,-1, 0, 1,-1, 1, 0,-1, 1, 0,-1, 1, 0,-1, 1, 0,-1};
int mx[]={ 1,-1, 0, 0, 0, 0};
int my[]={ 0, 0, 1,-1, 0, 0};
int mz[]={ 0, 0, 0, 0, 1,-1};
map<P3,int> id;
set<P3> umes;
map<int,set<int>> divi;
int cnt;
bool used[MAX];
bool ume[MAX];

bool outer(int x,int y, int z ){
  if( x < 0 || x >= A || y < 0 || y >= B || z < 0 || z >= C ) return true;
  return false;
}

bool check( int x,int y,int z, bool f = false ){
  if( id.count( P3( x, y, z ) ) == 0 ) return false;
  int v = id[ P3(x,y,z) ];
  if( used[ v ] ) return false;
  if( f && !ume[ v ] ) return false;
  if( !f && ume[ v ] ) return false;
  return true;
}

void bfs(int x,int y,int z, bool f = false ){
  int v = id[P3(x,y,z)];
  if( used[v] ) return;
  queue<P3> q;
  q.push( P3(x,y,z) );
  used[ v ] = true;
  while( !q.empty() ){
    P3 p = q.front(); q.pop();
    x = p.x; y = p.y; z = p.z;
    v = id[ p ];
    int n = 6;
    if( f ) n = 27;
    for(int i=0;i<n;i++){
      int nx = x + dx[i], ny = y + dy[i], nz = z + dz[i];
      if(!f) nx = x + mx[i], ny = y + my[i], nz = z + mz[i];
      if( check( nx, ny, nz, f ) ) {
        int nv = id[ P3(nx,ny,nz) ];
        merge( v, nv );
        q.push( P3(nx,ny,nz) );
        used[ nv ] = true;
      }
    }
  }
}

int main(){
  cin >> A >> B >> C >> N;
  init();
  for(int i=0;i<N;i++){
    int x,y,z; cin >> x >> y >> z;
    for(int j=0;j<27;j++){
      int nx = x + dx[j], ny = y + dy[j], nz = z + dz[j];
      if( outer( nx, ny, nz ) ) continue;
      if( !id.count( P3( nx,ny,nz) ) ) 
        id[ P3(nx,ny,nz) ] = cnt++;     
    }
    umes.insert( P3(x,y,z) );
    ume[id[P3(x,y,z)]] = true;
  }
  
  for( auto it = id.begin(); it != id.end(); it++ ){
    P3 np = it->first;
    int v = it->second;
    if( ume[v] ) 
      bfs( np.x, np.y, np.z, true );
    else
      bfs( np.x, np.y, np.z );
  }

  for( auto it = umes.begin(); it != umes.end(); it++ ){
    P3 p = *it;
    int v = find( id[p] );
    for(int i=0;i<27;i++){
      int nx = p.x + dx[i], ny = p.y + dy[i], nz = p.z + dz[i];
      if( id.count( P3(nx,ny,nz) ) == 0 ) continue;
      if( umes.count( P3( nx, ny, nz ) ) ) continue;
      divi[ v ].insert( find( id[ P3(nx,ny,nz) ] ) );
    }
  }

  int res = 1;
  for( auto it = divi.begin(); it != divi.end(); it++ ){
    res += it->second.size()-1;
  }
  cout << res << endl;
  
}
accuracy: 1
time_ms: 820
memory_kb: 43032
final_rank: 7

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

int A,B,C,N;
const int MAX = 20000*30;
int d[MAX];
void init(){ memset( d, -1, sizeof( d ) ); }
int find(int a){ return d[a]<0?a:(d[a]=find(d[a])); }
bool merge(int a, int b){
  a = find(a); b = find(b);
  if( a == b ) return false;
  if( d[a] > d[b] ) swap( a, b );
  d[a] += d[b]; d[b] = a;
  return true;
}
bool same(int a,int b){
  return find(a) == find(b);
}

struct P3{
  int x,y,z;
  P3(){}
  P3(int x,int y,int z) : x(x),y(y),z(z) {}
  bool operator<(const P3& p) const {
    if( x == p.x )
      if( y == p.y )
        return z < p.z;
      else
        return y < p.y;
    else
      return x< p.x;
  }
};

int dx[]={ 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,-1,-1,-1,-1,-1,-1,-1,-1};
int dy[]={ 1, 1, 1, 0, 0, 0, 1,-1,-1, 1, 1, 1, 0, 0, 0,-1,-1,-1, 1, 1, 1, 0, 0, 0,-1,-1,-1};
int dz[]={ 1, 0,-1, 1, 0,-1, 1, 0,-1, 1, 0,-1, 0, 1,-1, 1, 0,-1, 1, 0,-1, 1, 0,-1, 1, 0,-1};
int mx[]={ 1,-1, 0, 0, 0, 0};
int my[]={ 0, 0, 1,-1, 0, 0};
int mz[]={ 0, 0, 0, 0, 1,-1};
map<P3,int> id;
set<P3> umes;
map<int,set<int>> divi;
int cnt;
bool used[MAX];
bool ume[MAX];

bool outer(int x,int y, int z ){
  if( x < 0 || x >= A || y < 0 || y >= B || z < 0 || z >= C ) return true;
  return false;
}

bool check( int x,int y,int z, bool f = false ){
  if( id.count( P3( x, y, z ) ) == 0 ) return false;
  int v = id[ P3(x,y,z) ];
  if( used[ v ] ) return false;
  if( f && !ume[ v ] ) return false;
  if( !f && ume[ v ] ) return false;
  return true;
}
/*
void dfs(int x,int y, int z, bool f = false){
  cout << x << " " << y << " " <<z << endl;
  int v = id[ P3(x,y,z) ];
  if( used[ v ] ) return;
  used[ v ] = true;
  int n = 6;
  if( f ) n = 27;
  for(int i=0;i<n;i++){
    int nx = x + dx[i], ny = y + dy[i], nz = z + dz[i];
    if(!f) nx = x + mx[i], ny = y + my[i], nz = z + mz[i];
    if( check( nx, ny, nz, f ) ) {
      // cout << x << " " << y << " " << z << "  -> " << nx << " " << ny << " " << nz << endl;
      // cout << "merge " << v << " "<< id[P3(nx,ny,nz)] << endl;
      merge( v, id[ P3(nx,ny,nz) ] );
      dfs( nx, ny, nz, f );
    }
  }
}
*/
void bfs(int x,int y,int z, bool f = false ){
  int v = id[P3(x,y,z)];
  if( used[v] ) return;
  queue<P3> q;
  q.push( P3(x,y,z) );
  used[ v ] = true;
  while( !q.empty() ){
    P3 p = q.front(); q.pop();
    x = p.x; y = p.y; z = p.z;
    v = id[ p ];
    int n = 6;
    if( f ) n = 27;
    for(int i=0;i<n;i++){
      int nx = x + dx[i], ny = y + dy[i], nz = z + dz[i];
      if(!f) nx = x + mx[i], ny = y + my[i], nz = z + mz[i];
      if( check( nx, ny, nz, f ) ) {
        int nv = id[ P3(nx,ny,nz) ];
        merge( v, nv );
        q.push( P3(nx,ny,nz) );
        used[ nv ] = true;
      }
    }
  }
}

int main(){
  cin >> A >> B >> C >> N;
  init();
  for(int i=0;i<N;i++){
    int x,y,z; cin >> x >> y >> z;
    for(int j=0;j<27;j++){
      int nx = x + dx[j], ny = y + dy[j], nz = z + dz[j];
      if( outer( nx, ny, nz ) ) continue;
      if( !id.count( P3( nx,ny,nz) ) ) 
        id[ P3(nx,ny,nz) ] = cnt++;     
    }
    umes.insert( P3(x,y,z) );
    ume[id[P3(x,y,z)]] = true;
  }
  
  for( auto it = id.begin(); it != id.end(); it++ ){
    P3 np = it->first;
    int v = it->second;
    if( ume[v] ) 
      bfs( np.x, np.y, np.z, true );
    else
      bfs( np.x, np.y, np.z );
  }

  for( auto it = umes.begin(); it != umes.end(); it++ ){
    P3 p = *it;
    int v = find( id[p] );
    for(int i=0;i<27;i++){
      int nx = p.x + dx[i], ny = p.y + dy[i], nz = p.z + dz[i];
      if( id.count( P3(nx,ny,nz) ) == 0 ) continue;
      if( umes.count( P3( nx, ny, nz ) ) ) continue;
      //cout << nx << " " << ny << " "<< nz << " = " << find(id[P3(nx,ny,nz)]) << " <= " << v << endl;
      divi[ v ].insert( find( id[ P3(nx,ny,nz) ] ) );
    }
  }

  int res = 1;
  for( auto it = divi.begin(); it != divi.end(); it++ ){
    res += it->second.size()-1;
  }
  cout << res << endl;
  
}
accuracy: 1
time_ms: 830
memory_kb: 42932
final_rank: 8

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

int A,B,C,N;
const int MAX = 20000*30;
int d[MAX];
void init(){ memset( d, -1, sizeof( d ) ); }
int find(int a){ return d[a]<0?a:(d[a]=find(d[a])); }
bool merge(int a, int b){
  a = find(a); b = find(b);
  if( a == b ) return false;
  if( d[a] > d[b] ) swap( a, b );
  d[a] += d[b]; d[b] = a;
  return true;
}
bool same(int a,int b){
  return find(a) == find(b);
}

struct P3{
  int x,y,z;
  P3(){}
  P3(int x,int y,int z) : x(x),y(y),z(z) {}
  bool operator<(const P3& p) const {
    if( x == p.x )
      if( y == p.y )
        return z < p.z;
      else
        return y < p.y;
    else
      return x< p.x;
  }
};

int dx[]={ 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,-1,-1,-1,-1,-1,-1,-1,-1};
int dy[]={ 1, 1, 1, 0, 0, 0, 1,-1,-1, 1, 1, 1, 0, 0, 0,-1,-1,-1, 1, 1, 1, 0, 0, 0,-1,-1,-1};
int dz[]={ 1, 0,-1, 1, 0,-1, 1, 0,-1, 1, 0,-1, 0, 1,-1, 1, 0,-1, 1, 0,-1, 1, 0,-1, 1, 0,-1};
int mx[]={ 1,-1, 0, 0, 0, 0};
int my[]={ 0, 0, 1,-1, 0, 0};
int mz[]={ 0, 0, 0, 0, 1,-1};
map<P3,int> id;
set<P3> umes;
map<int,set<int>> divi;
int cnt;
bool used[MAX];
bool ume[MAX];

bool outer(int x,int y, int z ){
  if( x < 0 || x >= A || y < 0 || y >= B || z < 0 || z >= C ) return true;
  return false;
}

bool check( int x,int y,int z, bool f = false ){
  if( id.count( P3( x, y, z ) ) == 0 ) return false;
  int v = id[ P3(x,y,z) ];
  if( used[ v ] ) return false;
  if( f && !ume[ v ] ) return false;
  if( !f && ume[ v ] ) return false;
  return true;
}

void dfs(int x,int y, int z, bool f = false){
  int v = id[ P3(x,y,z) ];
  if( used[ v ] ) return;
  used[ v ] = true;
  int n = 6;
  if( f ) n = 27;
  for(int i=0;i<n;i++){
    int nx = x + dx[i], ny = y + dy[i], nz = z + dz[i];
    if(!f) nx = x + mx[i], ny = y + my[i], nz = z + mz[i];
    if( check( nx, ny, nz, f ) ) {
      // cout << x << " " << y << " " << z << "  -> " << nx << " " << ny << " " << nz << endl;
      // cout << "merge " << v << " "<< id[P3(nx,ny,nz)] << endl;
      merge( v, id[ P3(nx,ny,nz) ] );
      dfs( nx, ny, nz, f );
    }
  }
}

int main(){
  cin >> A >> B >> C >> N;
  init();
  for(int i=0;i<N;i++){
    int x,y,z; cin >> x >> y >> z;
    for(int j=0;j<27;j++){
      int nx = x + dx[j], ny = y + dy[j], nz = z + dz[j];
      if( outer( nx, ny, nz ) ) continue;
      if( !id.count( P3( nx,ny,nz) ) ) 
        id[ P3(nx,ny,nz) ] = cnt++;     
    }
    umes.insert( P3(x,y,z) );
    ume[id[P3(x,y,z)]] = true;
  }

  
  for( auto it = id.begin(); it != id.end(); it++ ){
    P3 np = it->first;
    int v = it->second;
    if( ume[v] ) 
      dfs( np.x, np.y, np.z, true );
    else
      dfs( np.x, np.y, np.z );
  }

  for( auto it = umes.begin(); it != umes.end(); it++ ){
    P3 p = *it;
    int v = find( id[p] );
    //cout << p.x << " " << p.y << " " << p.z << " -> " << v << endl;
    for(int i=0;i<27;i++){
      int nx = p.x + dx[i], ny = p.y + dy[i], nz = p.z + dz[i];
      if( id.count( P3(nx,ny,nz) ) == 0 ) continue;
      if( umes.count( P3( nx, ny, nz ) ) ) continue;
      //cout << nx << " " << ny << " "<< nz << " = " << id[P3(nx,ny,nz)] << " <= " << v << endl;
      divi[ v ].insert( find( id[ P3(nx,ny,nz) ] ) );
    }
  }

  int res = 1;
  for( auto it = divi.begin(); it != divi.end(); it++ ){
    res += it->second.size()-1;
  }
  cout << res << endl;
  
}
accuracy: 0.10606060606060606
time_ms: 290
memory_kb: 38648
final_rank: 14

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

int A,B,C,N;
const int MAX = 20000*30;
int d[MAX];
void init(){ memset( d, -1, sizeof( d ) ); }
int find(int a){ return d[a]<0?a:(d[a]=find(d[a])); }
bool merge(int a, int b){
  a = find(a); b = find(b);
  if( a == b ) return false;
  if( d[a] > d[b] ) swap( a, b );
  d[a] += d[b]; d[b] = a;
  return true;
}
bool same(int a,int b){
  return find(a) == find(b);
}

struct P3{
  int x,y,z;
  P3(){}
  P3(int x,int y,int z) : x(x),y(y),z(z) {}
  bool operator<(const P3& p) const {
    if( x == p.x )
      if( y == p.y )
        return z < p.z;
      else
        return y < p.y;
    else
      return x< p.x;
  }
};

int dx[]={ 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,-1,-1,-1,-1,-1,-1,-1,-1};
int dy[]={ 1, 1, 1, 0, 0, 0, 1,-1,-1, 1, 1, 1, 0, 0, 0,-1,-1,-1, 1, 1, 1, 0, 0, 0,-1,-1,-1};
int dz[]={ 1, 0,-1, 1, 0,-1, 1, 0,-1, 1, 0,-1, 0, 1,-1, 1, 0,-1, 1, 0,-1, 1, 0,-1, 1, 0,-1};
int mx[]={ 1,-1, 0, 0, 0, 0};
int my[]={ 0, 0, 1,-1, 0, 0};
int mz[]={ 0, 0, 0, 0, 1,-1};
map<P3,int> id;
set<P3> umes;
map<int,set<int>> divi;
int cnt;
bool used[1000000];
bool ume[1000000];

bool outer(int x,int y, int z ){
  if( x < 0 || x >= A || y < 0 || y >= B || z < 0 || z >= C ) return true;
  return false;
}

bool check( int x,int y,int z, bool f = false ){
  if( outer( x, y, z ) ) return false;
  if( id.count( P3( x, y, z ) ) == 0 ) return false;
  int v = id[ P3(x,y,z) ];
  if( used[ v ] ) return false;
  if( f && !ume[ v ] ) return false;
  if( !f && ume[ v ] ) return false;
  return true;
}

void dfs(int x,int y, int z, bool f = false){
  int v = id[ P3(x,y,z) ];
  if( used[ v ] ) return;
  used[ v ] = true;
  int n = 6;
  if( f ) n = 27;
  for(int i=0;i<n;i++){
    int nx = x + dx[i], ny = y + dy[i], nz = z + dz[i];
    if(!f) nx = x + mx[i], ny = y + my[i], nz = z + mz[i];
    if( check( nx, ny, nz, f ) ) {
      // cout << x << " " << y << " " << z << "  -> " << nx << " " << ny << " " << nz << endl;
      // cout << "merge " << v << " "<< id[P3(nx,ny,nz)] << endl;
      merge( v, id[ P3(nx,ny,nz) ] );
      dfs( nx, ny, nz, f );
    }
  }
}

int main(){
  cin >> A >> B >> C >> N;
  init();
  for(int i=0;i<N;i++){
    int x,y,z; cin >> x >> y >> z;
    for(int j=0;j<27;j++){
      int nx = x + dx[j], ny = y + dy[j], nz = z + dz[j];
      if( outer( nx, ny, nz ) ) continue;
      if( !id.count( P3( nx,ny,nz) ) ) 
        id[ P3(nx,ny,nz) ] = cnt++;     
    }
    umes.insert( P3(x,y,z) );
    ume[id[P3(x,y,z)]] = true;
  }

  
  for( auto it = id.begin(); it != id.end(); it++ ){
    P3 np = it->first;
    int id = it->second;
    if( ume[id] ) 
      dfs( np.x, np.y, np.z, true );
    else
      dfs( np.x, np.y, np.z );
  }

  memset( used,0,sizeof( used ) );
  for( auto it = umes.begin(); it != umes.end(); it++ ){
    P3 p = *it;
    int v = find( id[p] );
    //cout << p.x << " " << p.y << " " << p.z << " -> " << v << endl;
    for(int i=0;i<27;i++){
      int nx = p.x + dx[i], ny = p.y + dy[i], nz = p.z + dz[i];
      if( id.count( P3(nx,ny,nz) ) == 0 ) continue;
      if( umes.count( P3( nx, ny, nz ) ) ) continue;
      //cout << nx << " " << ny << " "<< nz << " = " << id[P3(nx,ny,nz)] << " <= " << v << endl;
      divi[ v ].insert( find( id[ P3(nx,ny,nz) ] ) );
    }
  }

  int res = 1;
  for( auto it = divi.begin(); it != divi.end(); it++ ){
    res += it->second.size()-1;
  }
  cout << res << endl;
  
}
accuracy: 0.10606060606060606
time_ms: 290
memory_kb: 38708
final_rank: 15

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

int A,B,C,N;
const int MAX = 20000*30;
int d[MAX];
void init(){ memset( d, -1, sizeof( d ) ); }
int find(int a){ return d[a]<0?a:(d[a]=find(d[a])); }
bool merge(int a, int b){
  a = find(a); b = find(b);
  if( a == b ) return false;
  if( d[a] > d[b] ) swap( a, b );
  d[a] += d[b]; d[b] = a;
  return true;
}
bool same(int a,int b){
  return find(a) == find(b);
}

struct P3{
  int x,y,z;
  P3(){}
  P3(int x,int y,int z) : x(x),y(y),z(z) {}
  bool operator<(const P3& p) const {
    if( x == p.x )
      if( y == p.y )
        return z < p.z;
      else
        return y < p.y;
    else
      return x< p.x;
  }
};

int dx[]={ 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,-1,-1,-1,-1,-1,-1,-1,-1};
int dy[]={ 1, 1, 1, 0, 0, 0, 1,-1,-1, 1, 1, 1, 0, 0, 0,-1,-1,-1, 1, 1, 1, 0, 0, 0,-1,-1,-1};
int dz[]={ 1, 0,-1, 1, 0,-1, 1, 0,-1, 1, 0,-1, 0, 1,-1, 1, 0,-1, 1, 0,-1, 1, 0,-1, 1, 0,-1};
int mx[]={ 1,-1, 0, 0, 0, 0};
int my[]={ 0, 0, 1,-1, 0, 0};
int mz[]={ 0, 0, 0, 0, 1,-1};
map<P3,int> id;
set<P3> umes;
map<int,set<int>> divi;
int cnt;
bitset<1000000> used;
bitset<1000000> ume;

bool outer(int x,int y, int z ){
  if( x < 0 || x >= A || y < 0 || y >= B || z < 0 || z >= C ) return true;
  return false;
}

bool check( int x,int y,int z, bool f = false ){
  if( outer( x, y, z ) ) return false;
  if( id.count( P3( x, y, z ) ) == 0 ) return false;
  int v = id[ P3(x,y,z) ];
  if( used[ v ] ) return false;
  if( f && !ume[ v ] ) return false;
  if( !f && ume[ v ] ) return false;
  return true;
}

void dfs(int x,int y, int z, bool f = false){
  int v = id[ P3(x,y,z) ];
  if( used[ v ] ) return;
  used[ v ] = true;
  int n = 6;
  if( f ) n = 27;
  for(int i=0;i<n;i++){
    int nx = x + dx[i], ny = y + dy[i], nz = z + dz[i];
    if(!f) nx = x + mx[i], ny = y + my[i], nz = z + mz[i];
    if( check( nx, ny, nz, f ) ) {
      // cout << x << " " << y << " " << z << "  -> " << nx << " " << ny << " " << nz << endl;
      // cout << "merge " << v << " "<< id[P3(nx,ny,nz)] << endl;
      merge( v, id[ P3(nx,ny,nz) ] );
      dfs( nx, ny, nz, f );
    }
  }
}

int main(){
  cin >> A >> B >> C >> N;
  init();
  used = ume = 0;
  for(int i=0;i<N;i++){
    int x,y,z; cin >> x >> y >> z;
    for(int j=0;j<27;j++){
      int nx = x + dx[j], ny = y + dy[j], nz = z + dz[j];
      if( outer( nx, ny, nz ) ) continue;
      if( !id.count( P3( nx,ny,nz) ) ) 
        id[ P3(nx,ny,nz) ] = cnt++;     
    }
    umes.insert( P3(x,y,z) );
    ume[id[P3(x,y,z)]] = true;
  }

  
  for( auto it = id.begin(); it != id.end(); it++ ){
    P3 np = it->first;
    int id = it->second;
    if( ume[id] ) 
      dfs( np.x, np.y, np.z, true );
    else
      dfs( np.x, np.y, np.z );
  }
  
  used = 0;
  for( auto it = umes.begin(); it != umes.end(); it++ ){
    P3 p = *it;
    int v = find( id[p] );
    //cout << p.x << " " << p.y << " " << p.z << " -> " << v << endl;
    for(int i=0;i<27;i++){
      int nx = p.x + dx[i], ny = p.y + dy[i], nz = p.z + dz[i];
      if( id.count( P3(nx,ny,nz) ) == 0 ) continue;
      if( umes.count( P3( nx, ny, nz ) ) ) continue;
      //cout << nx << " " << ny << " "<< nz << " = " << id[P3(nx,ny,nz)] << " <= " << v << endl;
      divi[ v ].insert( find( id[ P3(nx,ny,nz) ] ) );
    }
  }

  int res = 1;
  for( auto it = divi.begin(); it != divi.end(); it++ ){
    res += it->second.size()-1;
  }
  cout << res << endl;
  
}
accuracy: 0.10606060606060606
time_ms: 280
memory_kb: 38472
final_rank: 13