#include "insects.h"
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <variant>
#include <map>
#include <random>
#include <chrono>
using namespace std;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
int randint(int l, int r) {return uniform_int_distribution<int>(l, r)(rng);}
struct DisjointSetUnion {
int n;
vector<int> fa, sz;
DisjointSetUnion(int _n) : n(_n), fa(n), sz(n, 1) {iota(fa.begin(), fa.end(), 0);}
int find(int x) {
if (fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
int size(int x) {
return sz[find(x)];
}
bool same(int x, int y) {
return find(x) == find(y);
}
void merge(int x, int y) {
x = find(x), y = find(y);
if (x == y) return;
fa[y] = x;
sz[x] += sz[y];
}
};
void move_inside(int i);
void move_outside(int i);
int press_button();
int min_cardinality(int N) {
int n = N;
vector<int> p(n);
iota(p.begin(), p.end(), 0);
shuffle(p.begin(), p.end(), rng);
DisjointSetUnion dsu(n);
int ans = n;
auto solve = [&] (auto solve, vector<int> p) -> vector<int> {
int n = p.size();
if (n <= 1) return p;
int threshold = 4;
if (n >= threshold) {
int m = n / 4;
auto vl = solve(solve, vector<int>(p.begin(), p.begin() + m));
auto vr = solve(solve, vector<int>(p.begin() + m, p.end()));
vector<int> arr = vl;
int ptr = 0;
auto move_pointer_to = [&] (int tar) {
while (ptr < tar) move_inside(arr[ptr++]);
while (ptr > tar) move_outside(arr[--ptr]);
};
move_pointer_to(arr.size());
vector<int> rem;
for (int x: vr) {
move_inside(x);
if (press_button() == 2) rem.push_back(x);
move_outside(x);
}
auto search = [&] (auto search, int ql, int qr, vector<int> uq) -> void {
if (ql == qr) {
for (int x: uq) dsu.merge(arr[ql], x);
return;
}
vector<int> ul, ur;
int qm = ql + qr >> 1;
move_pointer_to(qm + 1);
for (int x: uq) {
move_inside(x);
if (press_button() == 2) {
ul.push_back(x);
}else{
ur.push_back(x);
}
move_outside(x);
}
search(search, qm+1, qr, ur);
search(search, ql, qm, ul);
};
search(search, 0, arr.size() - 1, rem);
move_pointer_to(0);
}else{
vector<int> v;
for (int x: p) {
bool uni = true;
if (v.size()) {
move_inside(x);
for (int y: v) {
move_inside(y);
bool sm = press_button() == 2;
move_outside(y);
if (sm) {dsu.merge(x, y); uni = false; break;}
}
move_outside(x);
}
if (uni) v.push_back(x);
}
}
vector<int> res;
for (int x: p) if (dsu.find(x) == x) res.push_back(x);
return res;
};
solve(solve, p);
for (int i=0; i<n; i++) ans = min(ans, dsu.size(i));
return ans;
}