Problem:
Problem C:
Count the Regions
There are a number of rectangles on the
x-y
plane. The four sides of the rectangles are parallel to either the
x
-axis or the
y
-axis, and all of the rectangles reside within a range specified later. There are no other constraints on the coordinates of the rectangles.
The plane is partitioned into regions surrounded by the sides of one or more rectangles. In an example shown in Figure C.1, three rectangles overlap one another, and the plane is partitioned into eight regions.
Rectangles may overlap in more complex ways. For example, two rectangles may have overlapped sides, they may share their corner points, and/or they may be nested. Figure C.2 illustrates such cases.
Your job is to write a program that counts the number of the regions on the plane partitioned
by the rectangles.
Input
The input consists of multiple datasets. Each dataset is formatted as follows.
n
l
1
t
1
r
1
b
1
l
2
t
2
r
2
b
2
:
l
n
t
n
r
n
b
n
A dataset starts with
n
(1 ≤
n
≤ 50), the number of rectangles on the plane. Each of the
following
n
lines describes a rectangle. The
i
-th line contains four integers,
l
i
,
t
i
,
r
i
, and
b
i
, which are the coordinates of the
i
-th rectangle; (
l
i
,
t
i
) gives the
x-y
coordinates of the top left corner, and (
r
i
,
b
i
) gives that of the bottom right corner of the rectangle (0 ≤
l
i
<
r
i
≤ 10
6
, 0 ≤
b
i
<
t
i
≤ 10
6
, for 1 ≤
i
≤
n
). The four integers are separated by a space.
The input is terminated by a single zero.
Output
For each dataset, output a line containing the number of regions on the plane partitioned by the sides of the rectangles.
Figure C.1. Three rectangles partition the plane into eight regions. This corresponds to the first dataset of the sample input. The
x
- and
y
-axes are shown for illustration purposes only, and therefore they do not partition the plane.
Figure C.2. Rectangles overlapping in more complex ways. This corresponds to the
second dataset.
Sample Input
3
4 28 27 11
15 20 42 5
11 24 33 14
5
4 28 27 11
12 11 34 2
7 26 14 16
14 16 19 12
17 28 27 21
2
300000 1000000 600000 0
0 600000 1000000 300000
0
Output for the Sample Input
8
6
6

Submitted solutions:

code_snippet: #include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#include <algorithm>
using namespace std;
const int maxn = 555;
int l[maxn],r[maxn],t[maxn],b[maxn];
int X[maxn],Y[maxn],g[maxn][maxn];
map<int,int>mpx;
map<int,int>mpy;
int N,M;
int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};
void dfs(int i,int j){
    g[i][j]=1;
    for(int k=0;k<4;k++){
        int x=i+dx[k],y=j+dy[k];
        if(x<0 || x>N || y<0 || y>M) continue;
        if(!g[x][y]){
            dfs(x,y);
        }
    }
}

int main()
{
//    freopen("data.in","r",stdin);
    int n;
    while(scanf("%d",&n)!=EOF && n){
        for(int i=0;i<n;i++){
            scanf("%d%d%d%d",&l[i],&t[i],&r[i],&b[i]);
            X[i]=l[i];
            X[i+n]=r[i];
            Y[i]=t[i];
            Y[i+n]=b[i];
        }
        mpx.clear();
        mpx.clear();
        sort(X,X+n*2);
        sort(Y,Y+n*2);
        int t1=unique(X,X+n*2)-X;
        int t2=unique(Y,Y+n*2)-Y;
        for(int i=0;i<t1;i++)
            mpx[X[i]]=(i+1)*2;
        for(int i=0;i<t2;i++)
            mpy[Y[i]]=(i+1)*2;
        t1=(t1+1)*2+2;
        t2=(t2+1)*2+2;
        memset(g,0,sizeof g);
        for(int i=0;i<n;i++){
            int lb=mpx[l[i]],rb=mpx[r[i]],tb=mpy[t[i]],bb=mpy[b[i]];
//            printf("%d %d %d %d\n",lb,rb,tb,bb);
            for(int j=lb;j<=rb;j++)
                g[tb][j]=g[bb][j]=1;
            for(int j=bb;j<=tb;j++)
                g[j][lb]=g[j][rb]=1;
        }
        int ans=0;
        N=t2,M=t1;
        for(int i=0;i<=N;i++){
            for(int j=0;j<=M;j++){
                if(!g[i][j]){
                    dfs(i,j);
                    ans++;
                }
            }
        }
        printf("%d\n",ans);
    }

    return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 6460
final_rank: 16

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

using namespace std;

#define rep(i, a, b) for (int i = (int)(a); i < (int)(b); i++)
#define rrep(i, a, b) for (int i = (int)(b)-1; i >= (int)(a); i--)
#define ALL(v) (v).begin(), (v).end()
#define UNIQUE(v) sort(ALL(v)), (v).erase(unique(ALL(v)), (v).end())
#define SZ(v) (int)v.size()
#define MIN(v) *min_element(ALL(v))
#define MAX(v) *max_element(ALL(v))
#define LB(v, x) int(lower_bound(ALL(v), (x)) - (v).begin())
#define UB(v, x) int(upper_bound(ALL(v), (x)) - (v).begin())

using uint = unsigned int;
using ll = long long int;
using ull = unsigned long long;
using i128 = __int128_t;
using u128 = __uint128_t;
const int inf = 0x3fffffff;
const ll INF = 0x1fffffffffffffff;

template <typename T> inline bool chmax(T &a, T b) {
    if (a < b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T> inline bool chmin(T &a, T b) {
    if (a > b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T, typename U> T ceil(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? (x + y - 1) / y : x / y);
}
template <typename T, typename U> T floor(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? x / y : (x - y + 1) / y);
}
template <typename T> int popcnt(T x) {
    return __builtin_popcountll(x);
}
template <typename T> int topbit(T x) {
    return (x == 0 ? -1 : 63 - __builtin_clzll(x));
}
template <typename T> int lowbit(T x) {
    return (x == 0 ? -1 : __builtin_ctzll(x));
}

template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
    os << "P(" << p.first << ", " << p.second << ")";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const vector<T> &vec) {
    os << "{";
    for (int i = 0; i < vec.size(); i++) {
        os << vec[i] << (i + 1 == vec.size() ? "" : ", ");
    }
    os << "}";
    return os;
}
template <typename T, typename U>
ostream &operator<<(ostream &os, const map<T, U> &map_var) {
    os << "{";
    for (auto itr = map_var.begin(); itr != map_var.end(); itr++) {
        os << "(" << itr->first << ", " << itr->second << ")";
        itr++;
        if (itr != map_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const set<T> &set_var) {
    os << "{";
    for (auto itr = set_var.begin(); itr != set_var.end(); itr++) {
        os << *itr;
        ++itr;
        if (itr != set_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
#ifdef LOCAL
#define show(...) _show(0, #__VA_ARGS__, __VA_ARGS__)
#else
#define show(...) true
#endif
template <typename T> void _show(int i, T name) {
    cerr << '\n';
}
template <typename T1, typename T2, typename... T3>
void _show(int i, const T1 &a, const T2 &b, const T3 &...c) {
    for (; a[i] != ',' && a[i] != '\0'; i++)
        cerr << a[i];
    cerr << ":" << b << " ";
    _show(i + 1, a, c...);
}

/**
 * @brief template
 */

struct UnionFind{
    vector<int> par; int n;
    UnionFind(){}
    UnionFind(int _n):par(_n,-1),n(_n){}
    int root(int x){return par[x]<0?x:par[x]=root(par[x]);}
    bool same(int x,int y){return root(x)==root(y);}
    int size(int x){return -par[root(x)];}
    bool unite(int x,int y){
        x=root(x),y=root(y); if(x==y)return false;
        if(size(x)>size(y))swap(x,y);
        par[y]+=par[x]; par[x]=y; n--; return true;
    }
};

/**
 * @brief Union Find
 */

int main() {
while(1) {
    int N;
    cin >> N;
    if (N == 0) return 0;
    vector<int> A(N), B(N), C(N), D(N);
    vector<int> X = {-inf,inf}, Y = {-inf,inf};
    rep(i,0,N) {
        cin >> A[i] >> B[i] >> C[i] >> D[i];
        swap(B[i], D[i]);
        A[i] *= 2;
        B[i] *= 2;
        C[i] *= 2;
        D[i] *= 2;
        X.push_back(A[i]-1),X.push_back(A[i]),X.push_back(A[i]+1);
        Y.push_back(B[i]-1),Y.push_back(B[i]),Y.push_back(B[i]+1);
        X.push_back(C[i]-1),X.push_back(C[i]),X.push_back(C[i]+1);
        Y.push_back(D[i]-1),Y.push_back(D[i]),Y.push_back(D[i]+1);
    }
    UNIQUE(X), UNIQUE(Y);
    rep(i,0,N) {
        A[i] = LB(X,A[i]);
        B[i] = LB(Y,B[i]);
        C[i] = LB(X,C[i]);
        D[i] = LB(Y,D[i]);
    }
    int H = X.size(), W = Y.size();
    vector<vector<bool>> G(H,vector<bool>(W,true));
    rep(i,0,N) {
        rep(j,A[i],C[i]+1) G[j][B[i]] = G[j][D[i]] = false;
        rep(j,B[i],D[i]+1) G[A[i]][j] = G[C[i]][j] = false;
    }
    int ANS = 0;
    vector<vector<int>> used(H,vector<int>(W,false));
    int dx[4] = {1,0,-1,0}, dy[4] = {0,1,0,-1};
    rep(i,0,H) {
        rep(j,0,W) {
            if (used[i][j]) continue;
            if (!G[i][j]) continue;
            ANS++;
            queue<pair<int,int>> Q;
            Q.push({i,j});
            used[i][j] = true;
            while(!Q.empty()) {
                auto [x,y] = Q.front();
                Q.pop();
                rep(k,0,4) {
                    int nx = x + dx[k], ny = y + dy[k];
                    if (0 <= nx && nx < H && 0 <= ny && ny < W) {
                        if (!used[nx][ny] && G[nx][ny]) {
                            used[nx][ny] = true;
                            Q.push({nx,ny});
                        }
                    }
                }
            }
        }
    }
    cout << ANS << endl;
}
}
accuracy: 1
time_ms: 110
memory_kb: 3488
final_rank: 11

code_snippet: #include "bits/stdc++.h"
// @JASPER'S BOILERPLATE
using namespace std;
using ll = long long;

#ifdef JASPER
#include "debug.h"
#else
#define debug(...) 166
#endif

#define int long long

const int N = 55 * 2;

int x[N], y[N], X[N], Y[N];

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

ll a[N][N];

void solve(int i, int j, int val) {
    if (a[i][j] != val) return;
    a[i][j] = -1;
    for (int k = 0; k < 4; ++k) {
        int ni = i + dx[k];
        int nj = j + dy[k];
        if (0 <= ni && ni < N && 0 <= nj && nj < N) {
            solve(ni, nj, val);
        }
    }
}


signed main() {
    cin.tie(0) -> sync_with_stdio(0);
    
    #ifdef JASPER
        freopen("in1", "r", stdin);
    #endif

    int n;
    while (cin >> n) {
        if (n == 0) break;
        
        memset(a, 0, sizeof a);
        vector <int> valX, valY;
        for (int i = 0; i < n; ++i) {
            cin >> x[i] >> y[i] >> X[i] >> Y[i];
            valX.push_back(x[i]);
            valY.push_back(y[i]);

            valX.push_back(X[i]);
            valY.push_back(Y[i]);
        }

        sort(valX.begin(), valX.end());
        valX.resize(unique(valX.begin(), valX.end()) - valX.begin());

        sort(valY.begin(), valY.end());
        valY.resize(unique(valY.begin(), valY.end()) - valY.begin());

        for (int i = 0; i < n; ++i) {
            x[i] = (int) (lower_bound(valX.begin(), valX.end(), x[i]) - valX.begin() + 1);
            X[i] = (int) (lower_bound(valX.begin(), valX.end(), X[i]) - valX.begin() + 1);
            
            y[i] = (int) (lower_bound(valY.begin(), valY.end(), y[i]) - valY.begin() + 1);
            Y[i] = (int) (lower_bound(valY.begin(), valY.end(), Y[i]) - valY.begin() + 1);

            debug(x[i], y[i], X[i], Y[i]);

            for (int _x = x[i]; _x < X[i]; ++_x)
                for (int _y = Y[i]; _y < y[i]; ++_y) 
                    a[_x][_y] |= (1LL << i);
        }

        
        int ans = 0;
        for (int _x = 0; _x < N; ++_x) {
            for (int _y = 0; _y < N; ++_y) { 
                if (a[_x][_y] >= 0) {
                    solve(_x, _y, a[_x][_y]);
                    ++ans;
                }

            }
        }

        cout << ans << "\n";

    }

    return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 4008
final_rank: 7

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define ll long long
#define rep(i, a, b) for(ll i = a; i < b; i++)
#define all(x) (x).begin(), (x).end()

const vector<int> dx = {0, 1, 0, -1};
const vector<int> dy = {1, 0, -1, 0};

int main() {
    while (true) {
        int n;
        cin >> n;
        if (n == 0) return 0;
        vector<int> xs, ys;
        vector<int> l(n), t(n), r(n), b(n);
        rep(i,0,n){
            cin>>l[i]>>t[i]>>r[i]>>b[i];
            xs.push_back(l[i]);
            xs.push_back(r[i]);
            ys.push_back(t[i]);
            ys.push_back(b[i]);
        }
        xs.push_back(-1);
        ys.push_back(-1);
        sort(all(xs));
        xs.erase(unique(all(xs)), xs.end());
        sort(all(ys));
        ys.erase(unique(all(ys)), ys.end());

        const int M = 150;

        vector<vector<ll>> val(M, vector<ll>(M));
        rep(i,0,n){
            l[i]=lower_bound(all(xs), l[i])-xs.begin();
            r[i]=lower_bound(all(xs), r[i])-xs.begin();
            t[i]=lower_bound(all(ys), t[i])-ys.begin();
            b[i]=lower_bound(all(ys), b[i])-ys.begin();
            rep(x,l[i],r[i])rep(y,b[i],t[i]){
                val[x][y] |= 1LL<<i;
            }
        }

        int cnt = 0;
        vector<vector<bool>> visited(M, vector<bool>(M, false));
        rep(x,0,M)rep(y,0,M){
            if (visited[x][y]) continue;
            ++cnt;
            stack<pair<int,int>> st;
            st.push({x,y});
            visited[x][y] = true;
            while (!st.empty()) {
                auto [xx, yy] = st.top();
                st.pop();
                rep(k,0,4){
                    int nx = xx+dx[k], ny = yy+dy[k];
                    if (0 <= nx && nx < M && 0 <= ny && ny < M && !visited[nx][ny] && val[nx][ny] == val[x][y]) {
                        visited[nx][ny] = true;
                        st.push({nx, ny});
                    }
                }
            }
        }
        cout << cnt << "\n";
    }
}
accuracy: 1
time_ms: 50
memory_kb: 3640
final_rank: 10

code_snippet: #line 2 "cp-library/src/cp-template.hpp"
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;
using uint = unsigned int;
using ull  = unsigned long long;
using i32 = int;
using u32 = unsigned int;
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128_t;
template < class T > bool chmin(T& a, T b) { if(a > b) { a = b; return true; } return false; }
template < class T > bool chmax(T& a, T b) { if(a < b) { a = b; return true; } return false; }
template < class T, class U > T ceil (T x, U y) { return (x > 0 ? (x + y - 1) / y :           x / y); }
template < class T, class U > T floor(T x, U y) { return (x > 0 ?           x / y : (x - y + 1) / y); }
int popcnt(i32 x) { return __builtin_popcount(x); }
int popcnt(u32 x) { return __builtin_popcount(x); }
int popcnt(i64 x) { return __builtin_popcountll(x); }
int popcnt(u64 x) { return __builtin_popcountll(x); }

#line 2 "cp-library/src/utility/rep_itr.hpp"
template < class T > struct itr_rep {
    T i, d;
    constexpr itr_rep(const T i) noexcept : i(i), d(1) {}
    constexpr itr_rep(const T i, const T d) noexcept : i(i), d(d) {}
    void operator++() noexcept { i += d; }
    constexpr int operator*() const noexcept { return i; }
    constexpr bool operator!=(const itr_rep x) const noexcept { return d > 0 ? i < x.i : i > x.i; }
};

template < class T > struct rep {
    const itr_rep< T > s, t;
    constexpr rep(const T t) noexcept : s(0), t(t) {}
    constexpr rep(const T s, const T t) noexcept : s(s), t(t) {}
    constexpr rep(const T s, const T t, const T d) noexcept : s(s, d), t(t, d) {}
    constexpr auto begin() const noexcept { return s; }
    constexpr auto end  () const noexcept { return t; }
};

template < class T > struct revrep {
    const itr_rep < T > s, t;
    constexpr revrep(const T t) noexcept : s(t - 1, -1), t(-1, -1) {}
    constexpr revrep(const T s, const T t) noexcept : s(t - 1, -1), t(s - 1, -1) {}
    constexpr revrep(const T s, const T t, const T d) noexcept : s(t - 1, -d), t(s - 1, -d) {}
    constexpr auto begin() const noexcept { return s; }
    constexpr auto end  () const noexcept { return t; }
};
#line 3 "cp-library/src/utility/io.hpp"

/* 128bit integer */
istream& operator>>(istream& is, i128& x) {
    std::string s; is >> s;
    int pm = (s[0] == '-');
    x = 0;
    for(int i : rep(pm, int(s.size()))) x = x * 10 + (s[i] - '0');
    if(pm) x *= -1;
    return is;
}
ostream& operator<<(ostream& os, const i128& x) {
    if(x == 0) return os << '0';
    i128 y = x;
    if(y < 0) { os << '-'; y *= -1; }
    std::vector<int> ny;
    while(y > 0) { ny.push_back(y % 10); y /= 10; }
    for(int i : revrep(ny.size())) os << ny[i];
    return os;
}

template < class S, class T > istream& operator>>(istream& is,       std::pair< S, T >& x) { is >> x.first        >> x.second; return is; }
template < class S, class T > ostream& operator<<(ostream& os, const std::pair< S, T >& x) { os << x.first << " " << x.second; return os; }

namespace scanner {
    struct sca {
        template < class T > operator T() {
            T s; std::cin >> s; return s;
        }
    };
    struct vec {
        int n;
        vec(int n) : n(n) {}
        template < class T > operator std::vector< T >() {
            std::vector< T > v(n);
            for(T& x : v) std::cin >> x;
            return v;
        }
    };
    struct mat {
        int h, w;
        mat(int h, int w) : h(h), w(w) {}
        template < class T > operator std::vector< std::vector< T > >() {
            std::vector m(h, std::vector< T >(w));
            for(std::vector< T >& v : m) for(T& x : v) std::cin >> x;
            return m;
        }
    };
    struct speedup {
        speedup() {
            std::cin.tie(0);
            std::ios::sync_with_stdio(0);
        }
    } speedup_instance;
}
scanner::sca in() { return scanner::sca(); }
scanner::vec in(int n) { return scanner::vec(n); }
scanner::mat in(int h, int w) { return scanner::mat(h, w); }

namespace printer {
    void precision(int d) { std::cout << std::fixed << std::setprecision(d); }
    void flush() { std::cout.flush(); }
}

template < class T >
ostream& operator<<(ostream& os, const std::vector< T > a) {
    int n = a.size();
    for(int i : rep(n)) { os << a[i]; if(i != n - 1) os << ' '; }
    return os;
}

int print() { std::cout << '\n'; return 0; }
template < class head, class... tail > int print(head&& h, tail&&... t) {
    std::cout << h; if(sizeof...(tail)) std::cout << ' ';
    return print(std::forward<tail>(t)...);
}
template < class T > int print_n(const std::vector< T > a) {
    int n = a.size();
    for(int i : rep(n)) std::cout << a[i] << "\n";
    return 0;
}


#line 2 "cp-library/src/utility/key_val.hpp"

template < class K, class V >
struct key_val {
    K key; V val;
    key_val() {}
    key_val(K key, V val) : key(key), val(val) {}
    template < std::size_t Index >
    std::tuple_element_t< Index, key_val >& get() {
        if constexpr (Index == 0) return key;
        if constexpr (Index == 1) return val;
    }
};

namespace std {

template < class K, class V > struct tuple_size < key_val< K, V > > : integral_constant< size_t, 2 > {};
template < class K, class V > struct tuple_element < 0, key_val< K, V > > { using type = K; };
template < class K, class V > struct tuple_element < 1, key_val< K, V > > { using type = V; };

}
#line 2 "cp-library/src/utility/vec_op.hpp"
template < class T > key_val< int, T > max_of(const vector< T >& a) {
    int i = std::max_element(a.begin(), a.end()) - a.begin();
    return {i, a[i]};
}
template < class T > key_val< int, T > min_of(const vector< T >& a) {
    int i = std::min_element(a.begin(), a.end()) - a.begin();
    return {i, a[i]};
}
template < class S, class T > S sum_of(const vector< T >& a) {
    S sum = 0;
    for(const T x : a) sum += x;
    return sum;
}
template < class S, class T > vector< S > freq_of(const vector< T >& a, T L, T R) {
    vector< S > res(R - L, S(0));
    for(const T x : a) res[x - L] += 1;
    return res;
}
template < class S, class T > struct prefix_sum {
    vector< S > s;
    prefix_sum(const vector< T >& a) : s(a) {
        s.insert(s.begin(), S(0));
        for(int i : rep(a.size())) s[i + 1] += s[i];
    }
    // [L, R)
    S sum(int L, int R) { return s[R] - s[L]; }
};
#line 3 "cp-library/src/utility/heap.hpp"

template < class T > using heap_min = std::priority_queue< T, std::vector< T >, std::greater< T > >;
template < class T > using heap_max = std::priority_queue< T, std::vector< T >, std::less< T > >;

#line 27 "cp-library/src/cp-template.hpp"

#line 1 "cp-library/src/algorithm/bin_search.hpp"
template < class T, class F >
T bin_search(T ok, T ng, F f) {
    while(abs(ng - ok) > 1) {
        T mid = (ok + ng) / 2;
        (f(mid) ? ok : ng) = mid;
    }
    return ok;
}

template < class T, class F >
T bin_search_real(T ok, T ng, F f, int step = 80) {
    while(step--) {
        T mid = (ok + ng) / 2;
        (f(mid) ? ok : ng) = mid;
    }
    return ok;
}
#line 2 "cp-library/src/algorithm/argsort.hpp"

template < class T > std::vector< int > argsort(const std::vector< T > &a) {
    std::vector< int > ids((int)a.size());
    std::iota(ids.begin(), ids.end(), 0);
    std::sort(ids.begin(), ids.end(), [&](int i, int j) {
        return a[i] < a[j] || (a[i] == a[j] && i < j);
    });
    return ids;
}
#line 1 "macro.hpp"
namespace macro {

using size_type = int;
template < class container > void  sort(container& a) { std::sort(std:: begin(a), std:: end(a)); }
template < class container > void rsort(container& a) { std::sort(std::rbegin(a), std::rend(a)); }
template < class container > void reverse(container& a) { std::reverse(std::begin(a), std::end(a)); }
template < class container > void unique(container& a) {
    std::sort(std::begin(a), std::end(a));
    a.erase(std::unique(std::begin(a), std::end(a)), std::end(a));
}
template < class container > container  sorted(const container& a) { container b = a;  sort(b); return std::move(b); }
template < class container > container rsorted(const container& a) { container b = a; rsort(b); return std::move(b); }
template < class container, class compare > void sort(container& a, const compare& cmp) { std::sort(std::begin(a), std::end(a), cmp); }
template < class container, class compare > container sorted(const container& a, const compare& cmp) { container b = a; sort(b, cmp); return std::move(b); }
template < class container, class value > size_type lower_bound(const container& a, const value& x) { return std::lower_bound(std::begin(a), std::end(a), x) - std::begin(a); }
template < class container, class value > size_type upper_bound(const container& a, const value& x) { return std::upper_bound(std::begin(a), std::end(a), x) - std::begin(a); }

const std::vector<std::pair<size_type, size_type>> dir4 = { {+1,  0}, {-1,  0}, { 0, +1}, { 0, -1} };
const std::vector<std::pair<size_type, size_type>> dir8 = { {-1, -1}, {-1,  0}, {-1, +1}, { 0, -1}, { 0, +1}, {+1, -1}, {+1,  0}, {+1, +1} };

#ifdef _DEBUG
#define debug(x) std::cout << "[" << __LINE__ << "] " << #x << ": " << x << std::endl
#else
#define debug(x)
#endif

template < class container > void concat(container& a, const container& b) {
    a.insert(std::end(a), std::begin(b), std::end(b));
}
std::vector<size_type> iota(const size_type n) {
    std::vector<size_type> I(n);
    std::iota(std::begin(I), std::end(I), 0);
    return I;
}
template < class container > std::vector<size_type> sort_idx(const container& a) {
    const size_type n = a.size();
    std::vector<size_type> I = iota(n);
    std::sort(std::begin(I), std::end(I), [&](size_type i, size_type j) { return a[i] < a[j] or (a[i] == a[j] and i < j); });
    return I;
}
template < class container, class compare > std::vector<size_type> sort_idx(const container& a, const compare& cmp) {
    const size_type n = a.size();
    std::vector<size_type> I = iota(n);
    std::sort(std::begin(I), std::end(I), [&](size_type i, size_type j) { return cmp(a[i], a[j]) or (a[i] == a[j] and i < j); });
    return std::move(I);
}

struct grid {
    using size_type = int;
    size_type H, W;
    grid(const size_type H, const size_type W) : H(H), W(W) {}
    bool contains(const size_type i, const size_type j) {
        return 0 <= i and i < H and 0 <= j and j < W;
    }
};

} // namespace macro

using namespace macro;
#line 1 "cp-library/src/data_structure/union_find.hpp"
class union_find {
  public:
    union_find(int n) : data(n, -1) {}
    int unite(int x, int y) {
        x = root(x), y = root(y);
        if(x != y) {
            if(size(x) < size(y)) swap(x, y);
            data[x] += data[y];
            return data[y] = x;
        }
        return -1;
    }
    int root(int x) { return data[x] < 0 ? x : data[x] = root(data[x]); }
    int size(int x) { return -data[root(x)]; }
    bool same(int x, int y) { return root(x) == root(y); }

  private:
    vector<int> data;
};
#line 4 "A.cpp"

int solve(int n) {
    vector<int> x1(n), y1(n), x2(n), y2(n);
    for(int i : rep(n)) {
        x1[i] = in(), y2[i] = in(), x2[i] = in(), y1[i] = in();
        x1[i] *= 2; x2[i] *= 2; y1[i] *= 2; y2[i] *= 2;
    }
    vector<int> vx, vy;
    for(int i : rep(n)) {
        vx.push_back(x1[i] - 1);
        vx.push_back(x1[i]);
        vx.push_back(x1[i] + 1);
        vx.push_back(x2[i] - 1);
        vx.push_back(x2[i]);
        vx.push_back(x2[i] + 1);

        vy.push_back(y1[i] - 1);
        vy.push_back(y1[i]);
        vy.push_back(y1[i] + 1);
        vy.push_back(y2[i] - 1);
        vy.push_back(y2[i]);
        vy.push_back(y2[i] + 1);
    }
    unique(vx);
    unique(vy);
    for(int i : rep(n)) {
        x1[i] = lower_bound(vx, x1[i]);
        x2[i] = lower_bound(vx, x2[i]);
        y1[i] = lower_bound(vy, y1[i]);
        y2[i] = lower_bound(vy, y2[i]);
    }

    const int x_lim = vx.size();
    const int y_lim = vy.size();
    vector g(x_lim, vector(y_lim, 0));
    for(int i : rep(n)) {
        for(int x = x1[i]; x <= x2[i]; x++) g[x][y1[i]] = g[x][y2[i]] = 1;
        for(int y = y1[i]; y <= y2[i]; y++) g[x1[i]][y] = g[x2[i]][y] = 1;
    }

    union_find uf(x_lim * y_lim);
    auto h = [&](int x, int y) { return x * y_lim + y; };
    for(int x : rep(x_lim)) for(int y : rep(y_lim)) if(g[x][y] == 0) {
        if(x + 1 < x_lim and g[x + 1][y] == 0) uf.unite(h(x, y), h(x + 1, y));
        if(y + 1 < y_lim and g[x][y + 1] == 0) uf.unite(h(x, y), h(x, y + 1));
    }

    set<int> st;
    for(int x : rep(x_lim)) for(int y : rep(y_lim)) if(g[x][y] == 0) st.insert(uf.root(h(x, y)));
    return st.size();
}

int main() {
    while(true) {
        int n = in();
        if(n == 0) return 0;
        print(solve(n));
    }
}
accuracy: 1
time_ms: 150
memory_kb: 4316
final_rank: 15

code_snippet: #include "bits/stdc++.h"

using namespace std;

using ll=long long;

struct UnionFind{
    vector<ll>data;
    UnionFind(ll n):data(n,-1){}
    bool unite(ll a,ll b){
        a=root(a),b=root(b);
        if(a==b)return false;
        if(-data[a]< -data[b])swap(a,b);
        data[a]+=data[b];
        data[b]=a;
        return true;
    }
    bool find(ll a,ll b){return root(a)==root(b);}
    ll root(ll a){
        return data[a]<0?a:data[a]=root(data[a]);
    }
    ll size(ll a){
        return -data[root(a)];
    }
};

bool solve(){
    int n;cin>>n;
    if(n==0)return false;
    vector<int>l(n),t(n),r(n),b(n);
    map<int,int>X;
    map<int,int>Y;
    const int INF=1e8;
    X[-INF]=1;
    X[INF]=1;
    Y[-INF]=1;
    Y[INF]=1;
    auto Set=[&](int v,map<int,int>&mp){
        mp[v-1]=1;
        mp[v]=1;
        mp[v+1]=1;
    };
    for (int i = 0; i < n; ++i) {
        cin>>l[i]>>t[i]>>r[i]>>b[i];
        Set(l[i],X);
        Set(r[i],X);
        Set(t[i],Y);
        Set(b[i],Y);
    }
    int h=0;
    for(auto &[i,val]:X){
        val=h++;
    }
    int w=0;
    for(auto &[j,val]:Y){
        val=w++;
    }
    vector z(h,vector<ll>(w));
    for (int i = 0; i < n; ++i) {
        auto li=X[l[i]],rj=Y[t[i]];
        auto ri=X[r[i]],lj=Y[b[i]];
        z[li][lj]^=(1LL<<i);
        z[li][rj]^=(1LL<<i);
        z[ri][lj]^=(1LL<<i);
        z[ri][rj]^=(1LL<<i);
    }
    for (int i = 0; i < h; ++i) {
        for (int j = 1; j < w; ++j) {
            z[i][j]^=z[i][j-1];
        }
    }
    for (int i =1; i < h; ++i) {
        for (int j = 0; j < w; ++j) {
            z[i][j]^=z[i-1][j];
        }
    }
    UnionFind uni(h*w);
    vector<int>dx={0,-1,0,1};
    vector<int>dy={1,0,-1,0};
    for (int i = 0; i < h; ++i) {
        for (int j = 0; j < w; ++j) {
            for (int k = 0; k < 4; ++k) {
                auto i2=i+dx[k],j2=j+dy[k];
                if(i2<0 or i2>=h or j2<0 or j2>=w)continue;
                if(z[i][j]==z[i2][j2]){
                    uni.unite(i*w+j,i2*w+j2);
                }
            }
        }
    }
    int ans=0;
    for (int i = 0; i < h; ++i) {
        for (int j = 0; j < w; ++j) {
            if(uni.root(i*w+j)==i*w+j){
                ans++;
            }
        }
    }
    cout<<ans<<"\n";
    return true;
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    while(solve());
    return 0;
}
accuracy: 1
time_ms: 180
memory_kb: 4616
final_rank: 17

code_snippet: // #define _GLIBCXX_DEBUG
#pragma GCC optimize("O2,no-stack-protector,unroll-loops,fast-math")
#include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for (int i = 0; i < int(n); i++)
#define per(i, n) for (int i = (n)-1; 0 <= i; i--)
#define rep2(i, l, r) for (int i = (l); i < int(r); i++)
#define per2(i, l, r) for (int i = (r)-1; int(l) <= i; i--)
#define each(e, v) for (auto& e : v)
#define MM << " " <<
#define pb push_back
#define eb emplace_back
#define all(x) begin(x), end(x)
#define rall(x) rbegin(x), rend(x)
#define sz(x) (int)x.size()
template <typename T> void print(const vector<T>& v, T x = 0) {
    int n = v.size();
    for (int i = 0; i < n; i++) cout << v[i] + x << (i == n - 1 ? '\n' : ' ');
    if (v.empty()) cout << '\n';
}
using ll = long long;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
template <typename T> bool chmax(T& x, const T& y) {
    return (x < y) ? (x = y, true) : false;
}
template <typename T> bool chmin(T& x, const T& y) {
    return (x > y) ? (x = y, true) : false;
}
template <class T>
using minheap = std::priority_queue<T, std::vector<T>, std::greater<T>>;
template <class T> using maxheap = std::priority_queue<T>;
template <typename T> int lb(const vector<T>& v, T x) {
    return lower_bound(begin(v), end(v), x) - begin(v);
}
template <typename T> int ub(const vector<T>& v, T x) {
    return upper_bound(begin(v), end(v), x) - begin(v);
}
template <typename T> void rearrange(vector<T>& v) {
    sort(begin(v), end(v));
    v.erase(unique(begin(v), end(v)), end(v));
}

// __int128_t gcd(__int128_t a, __int128_t b) {
//     if (a == 0)
//         return b;
//     if (b == 0)
//         return a;
//     __int128_t cnt = a % b;
//     while (cnt != 0) {
//         a = b;
//         b = cnt;
//         cnt = a % b;
//     }
//     return b;
// }

struct Union_Find_Tree {
    vector<int> data;
    const int n;
    int cnt;
 
    Union_Find_Tree(int n) : data(n, -1), n(n), cnt(n) {}
 
    int root(int x) {
        if (data[x] < 0) return x;
        return data[x] = root(data[x]);
    }
 
    int operator[](int i) { return root(i); }
 
    bool unite(int x, int y) {
        x = root(x), y = root(y);
        if (x == y) return false;
        if (data[x] > data[y]) swap(x, y);
        data[x] += data[y], data[y] = x;
        cnt--;
        return true;
    }
 
    int size(int x) { return -data[root(x)]; }
 
    int count() { return cnt; };
 
    bool same(int x, int y) { return root(x) == root(y); }
 
    void clear() {
        cnt = n;
        fill(begin(data), end(data), -1);
    }
};

template <int mod> struct Mod_Int {
    int x;

    Mod_Int() : x(0) {}

    Mod_Int(long long y) : x(y >= 0 ? y % mod : (mod - (-y) % mod) % mod) {}

    static int get_mod() { return mod; }

    Mod_Int& operator+=(const Mod_Int& p) {
        if ((x += p.x) >= mod) x -= mod;
        return *this;
    }

    Mod_Int& operator-=(const Mod_Int& p) {
        if ((x += mod - p.x) >= mod) x -= mod;
        return *this;
    }

    Mod_Int& operator*=(const Mod_Int& p) {
        x = (int)(1LL * x * p.x % mod);
        return *this;
    }

    Mod_Int& operator/=(const Mod_Int& p) {
        *this *= p.inverse();
        return *this;
    }

    Mod_Int& operator++() { return *this += Mod_Int(1); }

    Mod_Int operator++(int) {
        Mod_Int tmp = *this;
        ++*this;
        return tmp;
    }

    Mod_Int& operator--() { return *this -= Mod_Int(1); }

    Mod_Int operator--(int) {
        Mod_Int tmp = *this;
        --*this;
        return tmp;
    }

    Mod_Int operator-() const { return Mod_Int(-x); }

    Mod_Int operator+(const Mod_Int& p) const { return Mod_Int(*this) += p; }

    Mod_Int operator-(const Mod_Int& p) const { return Mod_Int(*this) -= p; }

    Mod_Int operator*(const Mod_Int& p) const { return Mod_Int(*this) *= p; }

    Mod_Int operator/(const Mod_Int& p) const { return Mod_Int(*this) /= p; }

    bool operator==(const Mod_Int& p) const { return x == p.x; }

    bool operator!=(const Mod_Int& p) const { return x != p.x; }

    Mod_Int inverse() const {
        assert(*this != Mod_Int(0));
        return pow(mod - 2);
    }

    Mod_Int pow(long long k) const {
        Mod_Int now = *this, ret = 1;
        for (; k > 0; k >>= 1, now *= now) {
            if (k & 1) ret *= now;
        }
        return ret;
    }

    friend ostream& operator<<(ostream& os, const Mod_Int& p) {
        return os << p.x;
    }

    friend istream& operator>>(istream& is, Mod_Int& p) {
        long long a;
        is >> a;
        p = Mod_Int<mod>(a);
        return is;
    }
};

ll mpow2(ll x, ll n, ll mod) {
    ll ans = 1;
    x %= mod;
    while (n != 0) {
        if (n & 1) ans = ans * x % mod;
        x = x * x % mod;
        n = n >> 1;
    }
    ans %= mod;
    return ans;
}

template <typename T> T modinv(T a, const T& m) {
    T b = m, u = 1, v = 0;
    while (b > 0) {
        T t = a / b;
        swap(a -= t * b, b);
        swap(u -= t * v, v);
    }
    return u >= 0 ? u % m : (m - (-u) % m) % m;
}

ll divide_int(ll a, ll b) {
    if (b < 0) a = -a, b = -b;
    return (a >= 0 ? a / b : (a - b + 1) / b);
}

// const int MOD = 1000000007;
const int MOD = 998244353;
using mint = Mod_Int<MOD>;

// ----- library -------
// ----- library -------

int main() {
    ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    cout << fixed << setprecision(15);

    while (1) {
        int n;
        cin >> n;
        if (!n)
            break;
        vector<int> l(n), r(n), u(n), d(n);
        rep(i, n) cin >> l[i] >> d[i] >> r[i] >> u[i];
        vector<int> xs, ys;
        rep(i, n) xs.eb(l[i]), xs.eb(r[i]), ys.eb(u[i]), ys.eb(d[i]);
        xs.eb(-1e9), xs.eb(1e9), ys.eb(-1e9), ys.eb(1e9);
        rearrange(xs), rearrange(ys);
        rep(i, n) l[i] = lb(xs, l[i]), r[i] = lb(xs, r[i]), u[i] = lb(ys, u[i]), d[i] = lb(ys, d[i]);
        int h = sz(ys) - 1, w = sz(xs) - 1;
        vector<vector<int>> rf(h, vector<int>(w, 1)), cf(h, vector<int>(w, 1));
        rep(i, n) {
            rep2(t, l[i], r[i]) rf[u[i] - 1][t] = 0, rf[d[i] - 1][t] = 0;
            rep2(t, u[i], d[i]) cf[t][l[i] - 1] = 0, cf[t][r[i] - 1] = 0;
        }
        Union_Find_Tree uf(h * w);
        rep(i, h - 1) rep(j, w) if (rf[i][j]) uf.unite(i * w + j, (i + 1) * w + j);
        rep(i, h) rep(j, w - 1) if (cf[i][j]) uf.unite(i * w + j, i * w + j + 1);
        cout << uf.count() << '\n';
    }
}
accuracy: 1
time_ms: 10
memory_kb: 3536
final_rank: 2

code_snippet: #include <bits/stdc++.h>
#include <complex>
#include <random>
using namespace std;
//#include <atcoder/all>
//using namespace atcoder;
using ll = long long;
using vll = vector<ll>;
using vvll = vector<vll>;
using vvvll = vector<vvll>;
using vvvvll = vector<vvvll>;
using vvvvvll = vector<vvvvll>;
using vvvvvvll = vector<vvvvvll>;
using vb = vector<bool>;
using vvb = vector<vb>;
using vvvb = vector<vvb>;
using vvvvb = vector<vvvb>;
using vd = vector<double>;
using vvd = vector<vd>;
using vvvd = vector<vvd>;
using vvvvd = vector<vvvd>;
using vvvvvd = vector<vvvvd>;
#define all(A) A.begin(),A.end()
#define ALL(A) A.begin(),A.end()
#define rep(i, n) for (ll i = 0; i < (ll) (n); i++)
using pqr = priority_queue<pair<ll, ll>, vector<pair<ll, ll>>, greater<pair<ll, ll>>>;
#define tN(t) (t==1?XN:YN)
#define tS(t) (t==1?XS:YS)
#define tA(t) (t==1?XA:YA)

template<class T>
bool chmax(T& p, T q, bool C = 1) {
    if (C == 0 && p == q) {
        return 1;
    }
    if (p < q) {
        p = q;
        return 1;
    }
    else {
        return 0;
    }
}

template<class T>
bool chmin(T& p, T q, bool C = 1) {
    if (C == 0 && p == q) {
        return 1;
    }
    if (p > q) {
        p = q;
        return 1;
    }
    else {
        return 0;
    }
}

ll gcd(ll(a), ll(b)) {
    if (b == 0)return a;
    ll c = a;
    while (a % b != 0) {
        c = a % b;
        a = b;
        b = c;
    }
    return b;
}
ll sqrtz(ll N) {
    ll L = 0;
    ll R = sqrt(N) + 10000;
    while (abs(R - L) > 1) {
        ll mid = (R + L) / 2;
        if (mid * mid <= N)L = mid;
        else R = mid;
    }
    return L;

}

vector<ll> fact, factinv, inv;
ll mod = 1e9 + 7;
void prenCkModp(ll n) {
    fact.resize(n + 5);
    factinv.resize(n + 5);
    inv.resize(n + 5);
    fact.at(0) = fact.at(1) = 1;
    factinv.at(0) = factinv.at(1) = 1;
    inv.at(1) = 1;
    for (ll i = 2; i < n + 5; i++) {
        fact.at(i) = (fact.at(i - 1) * i) % mod;
        inv.at(i) = mod - (inv.at(mod % i) * (mod / i)) % mod;
        factinv.at(i) = (factinv.at(i - 1) * inv.at(i)) % mod;
    }

}
ll nCk(ll n, ll k) {
    if (n < k) return 0;
    return fact.at(n) * (factinv.at(k) * factinv.at(n - k) % mod) % mod;
}
ll modPow(ll a, ll n, ll p) {
    ll res = 1;
    ll k = a;
    while (n > 0) {
        if (n % 2 == 1) {
            res *= k;
            if (res > p)res %= p;
        }
        k = k * k;
        if (k > p)k %= p;
        n /= 2;
    }
    return res;
}

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

    
    while(1){
        ll N;
        cin>>N;
        if(N==0)return 0;
        map<ll,ll> MX,MY;
        vector<pair<pair<ll,ll>,pair<ll,ll>>> P(N);
        rep(i,N){
            ll A,B,C,D;
            cin>>A>>B>>C>>D;
            swap(B,D);
            MX[A]=MX[C]=1;
            MY[B]=MY[D]=1;
            P[i]={{A,B},{C,D}};
        }
        ll k=0,p=0;
        for(auto x:MX){
            MX[x.first]=2*k+1;
            k++;
        }
        for(auto x:MY){
            MY[x.first]=2*p+1;
            p++;
        }
        vvll A(250,vll(250,0));
        rep(i,N){
            P[i].first.first=MX[P[i].first.first];
            P[i].first.second=MY[P[i].first.second];
            P[i].second.first=MX[P[i].second.first];
            P[i].second.second=MY[P[i].second.second];
            
            for(ll j=P[i].first.first;j<=P[i].second.first;j++){
                A[j][P[i].second.second]=1;
                A[j][P[i].first.second]=1;
            }
            for(ll j=P[i].first.second;j<=P[i].second.second;j++){
                A[P[i].second.first][j]=1;
                A[P[i].first.first][j]=1;
            }
        }
        //cout<<1<<endl;
        ll an=0;
        vll dx={1,0,-1,0};
        vll dy={0,1,0,-1};
        rep(i,250)rep(j,250){
            if(A[i][j]==1)continue;
            an++;
            queue<pair<ll,ll>> Q;
            Q.push({i,j});
            while(!Q.empty()){
                auto p=Q.front();
                Q.pop();
                if(A[p.first][p.second]==1)continue;
                A[p.first][p.second]=1;
                rep(d,4){
                    ll nx=p.first+dx[d];
                    ll ny=p.second+dy[d];
                    if(nx<0||ny<0||nx>=250||ny>=250)continue;
                    if(A[nx][ny]==1)continue;
                    Q.push({nx,ny});
                }
            }
        }
        cout<<an<<endl;
    }
}
accuracy: 1
time_ms: 100
memory_kb: 3824
final_rank: 13

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

#ifdef _RUTHEN
#include "debug.hpp"
#else
#define show(...) true
#endif

using ll = long long;
#define rep(i, n) for (int i = 0; i < (n); i++)
template <class T> using V = vector<T>;

struct UF {
    V<int> par;
    UF(int n) : par(n, -1) {}
    int leader(int x) { return par[x] < 0 ? x : par[x] = leader(par[x]); }
    bool merge(int x, int y) {
        x = leader(x), y = leader(y);
        if (x == y) return false;
        if (par[x] > par[y]) swap(x, y);
        par[x] += par[y];
        par[y] = x;
        return true;
    }
    int size(int x) { return -par[leader(x)]; }
};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    int N;
    while (cin >> N, N != 0) {
        V<int> l(N), t(N), r(N), b(N);
        rep(i, N) cin >> l[i] >> t[i] >> r[i] >> b[i];
        V<int> zx = {-1, 1000001}, zy = {-1, 1000001};
        rep(i, N) {
            zx.push_back(l[i]);
            zx.push_back(r[i]);
            zy.push_back(b[i]);
            zy.push_back(t[i]);
        }
        sort(zx.begin(), zx.end());
        zx.erase(unique(zx.begin(), zx.end()), zx.end());
        sort(zy.begin(), zy.end());
        zy.erase(unique(zy.begin(), zy.end()), zy.end());
        rep(i, N) {
            l[i] = lower_bound(zx.begin(), zx.end(), l[i]) - zx.begin();
            r[i] = lower_bound(zx.begin(), zx.end(), r[i]) - zx.begin();
            b[i] = lower_bound(zy.begin(), zy.end(), b[i]) - zy.begin();
            t[i] = lower_bound(zy.begin(), zy.end(), t[i]) - zy.begin();
        }
        int H = zx.size(), W = zy.size();
        V<V<ll>> imos(H + 1, V<ll>(W + 1, 0));
        rep(i, N) {
            imos[l[i]][b[i]] += 1LL << i;
            imos[l[i]][t[i]] -= 1LL << i;
            imos[r[i]][b[i]] -= 1LL << i;
            imos[r[i]][t[i]] += 1LL << i;
        }
        rep(x, H + 1) rep(y, W) imos[x][y + 1] += imos[x][y];
        rep(x, H) rep(y, W + 1) imos[x + 1][y] += imos[x][y];
        int M = (H + 1) * (W + 1);
        UF uf(M);
        const int dx[4] = {1, 0, -1, 0}, dy[4] = {0, 1, 0, -1};
        rep(x, H + 1) {
            rep(y, W + 1) {
                rep(k, 4) {
                    int nx = x + dx[k], ny = y + dy[k];
                    if (!(0 <= nx and nx <= H and 0 <= ny and ny <= W)) continue;
                    if (imos[x][y] == imos[nx][ny]) uf.merge(x * (W + 1) + y, nx * (W + 1) + ny);
                }
            }
        }
        int ans = 0;
        rep(x, H + 1) {
            rep(y, W + 1) {
                if (x * (W + 1) + y == uf.leader(x * (W + 1) + y)) {
                    ans++;
                }
            }
        }
        cout << ans << '\n';
    }
    return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 3444
final_rank: 3

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

#ifdef _RUTHEN
#include "debug.hpp"
#else
#define show(...) true
#endif

using ll = long long;
#define rep(i, n) for (int i = 0; i < (n); i++)
template <class T> using V = vector<T>;

struct UF {
    V<int> par;
    UF(int n) : par(n, -1) {}
    int leader(int x) { return par[x] < 0 ? x : par[x] = leader(par[x]); }
    bool merge(int x, int y) {
        x = leader(x), y = leader(y);
        if (x == y) return false;
        if (par[x] > par[y]) swap(x, y);
        par[x] += par[y];
        par[y] = x;
        return true;
    }
};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    int N;
    while (cin >> N, N != 0) {
        V<int> l(N), t(N), r(N), b(N);
        rep(i, N) cin >> l[i] >> t[i] >> r[i] >> b[i];
        V<int> zx = {-1, 1000001}, zy = {-1, 1000001};
        rep(i, N) {
            zx.push_back(l[i]);
            zx.push_back(r[i]);
            zy.push_back(b[i]);
            zy.push_back(t[i]);
        }
        sort(zx.begin(), zx.end());
        zx.erase(unique(zx.begin(), zx.end()), zx.end());
        sort(zy.begin(), zy.end());
        zy.erase(unique(zy.begin(), zy.end()), zy.end());
        rep(i, N) {
            l[i] = lower_bound(zx.begin(), zx.end(), l[i]) - zx.begin();
            r[i] = lower_bound(zx.begin(), zx.end(), r[i]) - zx.begin();
            b[i] = lower_bound(zy.begin(), zy.end(), b[i]) - zy.begin();
            t[i] = lower_bound(zy.begin(), zy.end(), t[i]) - zy.begin();
        }
        int H = zx.size(), W = zy.size();
        V<V<ll>> cum(H + 1, V<ll>(W + 1, 0));
        rep(i, N) {
            cum[l[i]][b[i]] += 1LL << i;
            cum[l[i]][t[i]] -= 1LL << i;
            cum[r[i]][b[i]] -= 1LL << i;
            cum[r[i]][t[i]] += 1LL << i;
        }
        rep(x, H) rep(y, W) cum[x + 1][y + 1] += cum[x + 1][y] + cum[x][y + 1] - cum[x][y];
        int M = (H + 1) * (W + 1);
        UF uf(M);
        const int dx[4] = {1, 0, -1, 0}, dy[4] = {0, 1, 0, -1};
        rep(x, H + 1) {
            rep(y, W + 1) {
                rep(k, 4) {
                    int nx = x + dx[k], ny = y + dy[k];
                    if (!(0 <= nx and nx <= H and 0 <= ny and ny <= W)) continue;
                    if (cum[x][y] == cum[nx][ny]) uf.merge(x * (W + 1) + y, nx * (W + 1) + ny);
                }
            }
        }
        int ans = 0;
        rep(x, H + 1) {
            rep(y, W + 1) {
                if (x * (W + 1) + y == uf.leader(x * (W + 1) + y)) {
                    ans++;
                }
            }
        }
        cout << ans << '\n';
    }
    return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 3448
final_rank: 4

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

#ifdef _RUTHEN
#include "debug.hpp"
#else
#define show(...) true
#endif

using ll = long long;
#define rep(i, n) for (int i = 0; i < (n); i++)
template <class T> using V = vector<T>;

struct UF {
    V<int> par;
    UF(int n) : par(n, -1) {}
    int leader(int x) { return par[x] < 0 ? x : par[x] = leader(par[x]); }
    bool merge(int x, int y) {
        x = leader(x), y = leader(y);
        if (x == y) return false;
        if (par[x] > par[y]) swap(x, y);
        par[x] += par[y];
        par[y] = x;
        return true;
    }
    int size(int x) { return -par[leader(x)]; }
};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    int N;
    while (cin >> N, N != 0) {
        V<int> l(N), t(N), r(N), b(N);
        rep(i, N) cin >> l[i] >> t[i] >> r[i] >> b[i];
        V<int> zx = {-1, 1000001}, zy = {-1, 1000001};
        rep(i, N) {
            zx.push_back(l[i]);
            zx.push_back(r[i]);
            zy.push_back(b[i]);
            zy.push_back(t[i]);
        }
        sort(zx.begin(), zx.end());
        zx.erase(unique(zx.begin(), zx.end()), zx.end());
        sort(zy.begin(), zy.end());
        zy.erase(unique(zy.begin(), zy.end()), zy.end());
        rep(i, N) {
            l[i] = lower_bound(zx.begin(), zx.end(), l[i]) - zx.begin();
            r[i] = lower_bound(zx.begin(), zx.end(), r[i]) - zx.begin();
            b[i] = lower_bound(zy.begin(), zy.end(), b[i]) - zy.begin();
            t[i] = lower_bound(zy.begin(), zy.end(), t[i]) - zy.begin();
        }
        int H = zx.size(), W = zy.size();
        V<V<ll>> cum(H + 1, V<ll>(W + 1, 0));
        rep(i, N) {
            cum[l[i]][b[i]] += 1LL << i;
            cum[l[i]][t[i]] -= 1LL << i;
            cum[r[i]][b[i]] -= 1LL << i;
            cum[r[i]][t[i]] += 1LL << i;
        }
        rep(x, H) rep(y, W) cum[x + 1][y + 1] += cum[x + 1][y] + cum[x][y + 1] - cum[x][y];
        int M = (H + 1) * (W + 1);
        UF uf(M);
        const int dx[4] = {1, 0, -1, 0}, dy[4] = {0, 1, 0, -1};
        rep(x, H + 1) {
            rep(y, W + 1) {
                rep(k, 4) {
                    int nx = x + dx[k], ny = y + dy[k];
                    if (!(0 <= nx and nx <= H and 0 <= ny and ny <= W)) continue;
                    if (cum[x][y] == cum[nx][ny]) uf.merge(x * (W + 1) + y, nx * (W + 1) + ny);
                }
            }
        }
        int ans = 0;
        rep(x, H + 1) {
            rep(y, W + 1) {
                if (x * (W + 1) + y == uf.leader(x * (W + 1) + y)) {
                    ans++;
                }
            }
        }
        cout << ans << '\n';
    }
    return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 3520
final_rank: 5

code_snippet: #line 1 "f.cpp"
/**
 *	author: nok0
 *	created: 2022.04.06 14:06:15
**/
#line 1 "/Users/nok0/Documents/Programming/nok0/atcoder/dsu.hpp"



#include <algorithm>
#include <cassert>
#include <vector>

namespace atcoder {

// Implement (union by size) + (path compression)
// Reference:
// Zvi Galil and Giuseppe F. Italiano,
// Data structures and algorithms for disjoint set union problems
struct dsu {
  public:
    dsu() : _n(0) {}
    explicit dsu(int n) : _n(n), parent_or_size(n, -1) {}

    int merge(int a, int b) {
        assert(0 <= a && a < _n);
        assert(0 <= b && b < _n);
        int x = leader(a), y = leader(b);
        if (x == y) return x;
        if (-parent_or_size[x] < -parent_or_size[y]) std::swap(x, y);
        parent_or_size[x] += parent_or_size[y];
        parent_or_size[y] = x;
        return x;
    }

    bool same(int a, int b) {
        assert(0 <= a && a < _n);
        assert(0 <= b && b < _n);
        return leader(a) == leader(b);
    }

    int leader(int a) {
        assert(0 <= a && a < _n);
        if (parent_or_size[a] < 0) return a;
        return parent_or_size[a] = leader(parent_or_size[a]);
    }

    int size(int a) {
        assert(0 <= a && a < _n);
        return -parent_or_size[leader(a)];
    }

    std::vector<std::vector<int>> groups() {
        std::vector<int> leader_buf(_n), group_size(_n);
        for (int i = 0; i < _n; i++) {
            leader_buf[i] = leader(i);
            group_size[leader_buf[i]]++;
        }
        std::vector<std::vector<int>> result(_n);
        for (int i = 0; i < _n; i++) {
            result[i].reserve(group_size[i]);
        }
        for (int i = 0; i < _n; i++) {
            result[leader_buf[i]].push_back(i);
        }
        result.erase(
            std::remove_if(result.begin(), result.end(),
                           [&](const std::vector<int>& v) { return v.empty(); }),
            result.end());
        return result;
    }

  private:
    int _n;
    // root node: -1 * component size
    // otherwise: parent
    std::vector<int> parent_or_size;
};

}  // namespace atcoder


#line 1 "/Users/nok0/Documents/Programming/nok0/cftemp.hpp"
#include <bits/stdc++.h>
using namespace std;

#pragma region Macros
// rep macro
#define foa(v, a) for(auto &v : a)
#define REPname(a, b, c, d, e, ...) e
#define REP(...) REPname(__VA_ARGS__, REP3, REP2, REP1, REP0)(__VA_ARGS__)
#define REP0(x) for(int i = 0; i < (x); ++i)
#define REP1(i, x) for(int i = 0; i < (x); ++i)
#define REP2(i, l, r) for(int i = (l); i < (r); ++i)
#define REP3(i, l, r, c) for(int i = (l); i < (r); i += (c))
#define REPSname(a, b, c, ...) c
#define REPS(...) REPSname(__VA_ARGS__, REPS1, REPS0)(__VA_ARGS__)
#define REPS0(x) for(int i = 1; i <= (x); ++i)
#define REPS1(i, x) for(int i = 1; i <= (x); ++i)
#define RREPname(a, b, c, d, e, ...) e
#define RREP(...) RREPname(__VA_ARGS__, RREP3, RREP2, RREP1, RREP0)(__VA_ARGS__)
#define RREP0(x) for(int i = (x)-1; i >= 0; --i)
#define RREP1(i, x) for(int i = (x)-1; i >= 0; --i)
#define RREP2(i, r, l) for(int i = (r)-1; i >= (l); --i)
#define RREP3(i, r, l, c) for(int i = (r)-1; i >= (l); i -= (c))
#define RREPSname(a, b, c, ...) c
#define RREPS(...) RREPSname(__VA_ARGS__, RREPS1, RREPS0)(__VA_ARGS__)
#define RREPS0(x) for(int i = (x); i >= 1; --i)
#define RREPS1(i, x) for(int i = (x); i >= 1; --i)

// name macro
#define pb push_back
#define eb emplace_back
#define SZ(x) ((int)(x).size())
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define popcnt(x) __builtin_popcountll(x)
template <class T = int>
using V = std::vector<T>;
template <class T = int>
using VV = std::vector<std::vector<T>>;
template <class T>
using pqup = std::priority_queue<T, std::vector<T>, std::greater<T>>;
using ll = long long;
using ld = long double;
using int128 = __int128_t;
using pii = std::pair<int, int>;
using pll = std::pair<long long, long long>;

// input macro
template <class T, class U>
std::istream &operator>>(std::istream &is, std::pair<T, U> &p) {
	is >> p.first >> p.second;
	return is;
}
template <class T>
std::istream &operator>>(std::istream &is, std::vector<T> &v) {
	for(T &i : v) is >> i;
	return is;
}
std::istream &operator>>(std::istream &is, __int128_t &a) {
	std::string s;
	is >> s;
	__int128_t ret = 0;
	for(int i = 0; i < s.length(); i++)
		if('0' <= s[i] and s[i] <= '9')
			ret = 10 * ret + s[i] - '0';
	a = ret * (s[0] == '-' ? -1 : 1);
	return is;
}
namespace scanner {
void scan(int &a) { std::cin >> a; }
void scan(long long &a) { std::cin >> a; }
void scan(std::string &a) { std::cin >> a; }
void scan(char &a) { std::cin >> a; }
void scan(char a[]) { std::scanf("%s", a); }
void scan(double &a) { std::cin >> a; }
void scan(long double &a) { std::cin >> a; }
template <class T, class U>
void scan(std::pair<T, U> &p) { std::cin >> p; }
template <class T>
void scan(std::vector<T> &a) { std::cin >> a; }
void INPUT() {}
template <class Head, class... Tail>
void INPUT(Head &head, Tail &...tail) {
	scan(head);
	INPUT(tail...);
}
}  // namespace scanner
#define VEC(type, name, size)     \
	std::vector<type> name(size); \
	scanner::INPUT(name)
#define VVEC(type, name, h, w)                                    \
	std::vector<std::vector<type>> name(h, std::vector<type>(w)); \
	scanner::INPUT(name)
#define INT(...)     \
	int __VA_ARGS__; \
	scanner::INPUT(__VA_ARGS__)
#define LL(...)            \
	long long __VA_ARGS__; \
	scanner::INPUT(__VA_ARGS__)
#define STR(...)             \
	std::string __VA_ARGS__; \
	scanner::INPUT(__VA_ARGS__)
#define CHAR(...)     \
	char __VA_ARGS__; \
	scanner::INPUT(__VA_ARGS__)
#define DOUBLE(...)     \
	double __VA_ARGS__; \
	scanner::INPUT(__VA_ARGS__)
#define LD(...)              \
	long double __VA_ARGS__; \
	scanner::INPUT(__VA_ARGS__)

// output-macro
template <class T, class U>
std::ostream &operator<<(std::ostream &os, const std::pair<T, U> &p) {
	os << p.first << " " << p.second;
	return os;
}
template <class T>
std::ostream &operator<<(std::ostream &os, const std::vector<T> &a) {
	for(int i = 0; i < int(a.size()); ++i) {
		if(i) os << " ";
		os << a[i];
	}
	return os;
}
std::ostream &operator<<(std::ostream &dest, __int128_t &value) {
	std::ostream::sentry s(dest);
	if(s) {
		__uint128_t tmp = value < 0 ? -value : value;
		char buffer[128];
		char *d = std::end(buffer);
		do {
			--d;
			*d = "0123456789"[tmp % 10];
			tmp /= 10;
		} while(tmp != 0);
		if(value < 0) {
			--d;
			*d = '-';
		}
		int len = std::end(buffer) - d;
		if(dest.rdbuf()->sputn(d, len) != len) {
			dest.setstate(std::ios_base::badbit);
		}
	}
	return dest;
}
template <class T>
void print(const T a) { std::cout << a << '\n'; }
template <class Head, class... Tail>
void print(Head H, Tail... T) {
	std::cout << H << ' ';
	print(T...);
}
template <class T>
void printel(const T a) { std::cout << a << '\n'; }
template <class T>
void printel(const std::vector<T> &a) {
	for(const auto &v : a)
		std::cout << v << '\n';
}
template <class Head, class... Tail>
void printel(Head H, Tail... T) {
	std::cout << H << '\n';
	printel(T...);
}
void Yes(const bool b = true) { std::cout << (b ? "Yes\n" : "No\n"); }
void No() { std::cout << "No\n"; }
void YES(const bool b = true) { std::cout << (b ? "YES\n" : "NO\n"); }
void NO() { std::cout << "NO\n"; }
void err(const bool b = true) {
	if(b) {
		std::cout << "-1\n", exit(0);
	}
}

//debug macro
namespace debugger {
template <class T>
void view(const std::vector<T> &a) {
	std::cerr << "{ ";
	for(const auto &v : a) {
		std::cerr << v << ", ";
	}
	std::cerr << "\b\b }";
}
template <class T>
void view(const std::vector<std::vector<T>> &a) {
	std::cerr << "{\n";
	for(const auto &v : a) {
		std::cerr << "\t";
		view(v);
		std::cerr << "\n";
	}
	std::cerr << "}";
}
template <class T, class U>
void view(const std::vector<std::pair<T, U>> &a) {
	std::cerr << "{\n";
	for(const auto &p : a) std::cerr << "\t(" << p.first << ", " << p.second << ")\n";
	std::cerr << "}";
}
template <class T, class U>
void view(const std::map<T, U> &m) {
	std::cerr << "{\n";
	for(const auto &p : m) std::cerr << "\t[" << p.first << "] : " << p.second << "\n";
	std::cerr << "}";
}
template <class T, class U>
void view(const std::pair<T, U> &p) { std::cerr << "(" << p.first << ", " << p.second << ")"; }
template <class T>
void view(const std::set<T> &s) {
	std::cerr << "{ ";
	for(auto &v : s) {
		view(v);
		std::cerr << ", ";
	}
	std::cerr << "\b\b }";
}

template <class T>
void view(const T &e) { std::cerr << e; }
}  // namespace debugger
#ifdef LOCAL
void debug_out() {}
template <typename Head, typename... Tail>
void debug_out(Head H, Tail... T) {
	debugger::view(H);
	std::cerr << ", ";
	debug_out(T...);
}
#define debug(...)                                                \
	do {                                                          \
		std::cerr << __LINE__ << " [" << #__VA_ARGS__ << "] : ["; \
		debug_out(__VA_ARGS__);                                   \
		std::cerr << "\b\b]\n";                                   \
	} while(false)
#else
#define debug(...) (void(0))
#endif

// vector macro
template <class T>
int lb(const std::vector<T> &a, const T x) { return std::distance((a).begin(), std::lower_bound((a).begin(), (a).end(), (x))); }
template <class T>
int ub(const std::vector<T> &a, const T x) { return std::distance((a).begin(), std::upper_bound((a).begin(), (a).end(), (x))); }
template <class T>
void UNIQUE(std::vector<T> &a) {
	std::sort(a.begin(), a.end());
	a.erase(std::unique(a.begin(), a.end()), a.end());
}
template <class T>
std::vector<T> press(std::vector<T> &a) {
	auto res = a;
	UNIQUE(res);
	for(auto &v : a)
		v = lb(res, v);
	return res;
}
#define SORTname(a, b, c, ...) c
#define SORT(...) SORTname(__VA_ARGS__, SORT1, SORT0, ...)(__VA_ARGS__)
#define SORT0(a) std::sort((a).begin(), (a).end())
#define SORT1(a, c) std::sort((a).begin(), (a).end(), [](const auto x, const auto y) { return x c y; })
template <class T>
void ADD(std::vector<T> &a, const T x = 1) {
	for(auto &v : a) v += x;
}
template <class T>
void SUB(std::vector<T> &a, const T x = 1) {
	for(auto &v : a) v -= x;
}
std::vector<std::pair<char, int>> rle(const string &s) {
	int n = s.size();
	std::vector<std::pair<char, int>> ret;
	for(int l = 0; l < n;) {
		int r = l + 1;
		for(; r < n and s[l] == s[r]; r++) {}
		ret.emplace_back(s[l], r - l);
		l = r;
	}
	return ret;
}
template <class T>
std::vector<std::pair<T, int>> rle(const std::vector<T> &v) {
	int n = v.size();
	std::vector<std::pair<T, int>> ret;
	for(int l = 0; l < n;) {
		int r = l + 1;
		for(; r < n and v[l] == v[r]; r++) {}
		ret.emplace_back(v[l], r - l);
		l = r;
	}
	return ret;
}
std::vector<int> iota(int n) {
	std::vector<int> p(n);
	std::iota(p.begin(), p.end(), 0);
	return p;
}
template <class T>
struct cum_vector {
public:
	cum_vector() = default;
	template <class U>
	cum_vector(const std::vector<U> &vec) : cum((int)vec.size() + 1) {
		for(int i = 0; i < (int)vec.size(); i++)
			cum[i + 1] = cum[i] + vec[i];
	}
	T prod(int l, int r) {
		return cum[r] - cum[l];
	}

private:
	std::vector<T> cum;
};

// math macro
template <class T, class U>
inline bool chmin(T &a, const U &b) { return a > b ? a = b, true : false; }
template <class T, class U>
inline bool chmax(T &a, const U &b) { return a < b ? a = b, true : false; }
template <class T>
T divup(T x, T y) { return (x + y - 1) / y; }
template <class T>
T POW(T a, long long n) {
	T ret = 1;
	while(n) {
		if(n & 1) ret *= a;
		a *= a;
		n >>= 1;
	}
	return ret;
}
// modpow
long long POW(long long a, long long n, const int mod) {
	long long ret = 1;
	a = (a % mod + mod) % mod;
	while(n) {
		if(n & 1) (ret *= a) %= mod;
		(a *= a) %= mod;
		n >>= 1;
	}
	return ret;
}
template <class T, class F>
T bin_search(T ok, T ng, const F &f) {
	while(abs(ok - ng) > 1) {
		T mid = (ok + ng) >> 1;
		(f(mid) ? ok : ng) = mid;
	}
	return ok;
}
template <class T, class F>
T bin_search(T ok, T ng, const F &f, int loop) {
	for(int i = 0; i < loop; i++) {
		T mid = (ok + ng) / 2;
		(f(mid) ? ok : ng) = mid;
	}
	return ok;
}

// others
struct fast_io {
	fast_io() {
		ios::sync_with_stdio(false);
		cin.tie(nullptr);
		cout << fixed << setprecision(15);
	}
} fast_io_;
const int inf = 1e9;
const ll INF = 1e18;
#pragma endregion

void main_();

int main() {
	main_();
	return 0;
}
#line 7 "f.cpp"

const int dx[4] = {1, 0, -1, 0};
const int dy[4] = {0, 1, 0, -1};
void main_() {
	while(true) {
		INT(n);
		if(!n) break;
		using T = tuple<int, int, int, int>;
		V<T> vec;
		V<> xp{-inf, inf}, yp{-inf, inf};
		REP(i, n) {
			INT(sx, gy, gx, sy);
			xp.pb(sx);
			xp.pb(gx);
			yp.pb(sy);
			yp.pb(gy);
			vec.pb(T(sx, sy, gx, gy));
		}
		auto rx = press(xp);
		auto ry = press(yp);
		int h = SZ(rx) - 1, w = SZ(ry) - 1;
		vector board(h, vector(w, 0));
		REP(k, n) {
			auto [sx, sy, gx, gy] = vec[k];
			sx = lb(rx, sx);
			gx = lb(rx, gx);
			sy = lb(ry, sy);
			gy = lb(ry, gy);
			//(sx, sy) - (gx,sy)
			REP(i, sx, gx) {
				board[i][sy - 1] |= 1 << 1;
				board[i][sy] |= 1 << 3;
				board[i][gy - 1] |= 1 << 1;
				board[i][gy] |= 1 << 3;
			}
			REP(i, sy, gy) {
				board[sx - 1][i] |= 1 << 0;
				board[sx][i] |= 1 << 2;
				board[gx - 1][i] |= 1 << 0;
				board[gx][i] |= 1 << 2;
			}
		}
		atcoder::dsu uf(h * w);
		REP(i, h) {
			REP(j, w) {
				int u = i * w + j;
				REP(k, 4) {
					if(!(board[i][j] >> k & 1)) {
						int nx = i + dx[k];
						int ny = j + dy[k];
						if(nx < 0 or nx >= h or ny < 0 or ny >= w) continue;
						int v = nx * w + ny;
						uf.merge(u, v);
					}
				}
			}
		}
		print(SZ(uf.groups()));
	}
}
accuracy: 1
time_ms: 30
memory_kb: 3872
final_rank: 8

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define rep(i,n) for(int (i)=0;(i)<(n);(i)++)
#define ll long long
#define pp pair<ll,ll>
#define ld long double
#define all(a) (a).begin(),(a).end()
#define mk make_pair
#define difine define
constexpr int inf=1000001000;
constexpr ll INF=2e18;
constexpr ll MOD=1000000007;
constexpr ll mod=998244353;
int dx[4]={1,-1,-1,1},dy[4]={1,-1,1,-1};

vector<int> a(4);
string s;
 
// #include <atcoder/all>
// typedef atcoder::modint1000000007 mint;
// typedef atcoder::modint998244353 mint;

int main() {
    while(true){
        int n;
        cin >> n;
        if (n==0) break;
        set<int> sx,sy;
        vector<int> l(n),t(n),r(n),b(n);
        rep(i,n){
            cin >> l[i] >> t[i] >> r[i] >> b[i];
            sx.insert(l[i]);
            sx.insert(r[i]);
            sy.insert(t[i]);
            sy.insert(b[i]);
        }
        map<int,int> mx,my;
        int x=1,y=1;
        for (auto it=sx.begin();it!=sx.end();it++){
            int f=*it;
            mx[f]=x;
            x++;
        }
        for (auto it=sy.begin();it!=sy.end();it++){
            int f=*it;
            my[f]=y;
            y++;
        }
        x+=2;
        y+=2;
        rep(i,n){
            l[i]=mx[l[i]];
            r[i]=mx[r[i]];
            t[i]=my[t[i]];
            b[i]=my[b[i]];
        }
        vector<vector<int>> d(x,vector<int>(y,0));
        int ans=0;
        rep(i,x){
            rep(j,y){
                if (d[i][j]==1) continue;
                // cout << i << " " << j << endl;
                ans++;
                d[i][j]=1;
                queue<pair<int,int>> q;
                q.push({i,j});
                while(!q.empty()){
                    auto [f,g]=q.front();
                    q.pop();
                    if (f+1!=x){
                        bool ok=true;
                        if (d[f+1][g]==1) ok=false;
                        rep(k,n){
                            if (g>=b[k] && g<t[k] && (f+1==l[k] || f+1==r[k])) ok=false;
                        }
                        if (ok){
                            q.push({f+1,g});
                            d[f+1][g]=1;
                        }
                    }
                    if (f-1!=-1){
                        bool ok=true;
                        if (d[f-1][g]==1) ok=false;
                        rep(k,n){
                            if (g>=b[k] && g<t[k] && (f==l[k] || f==r[k])) ok=false;
                        }
                        if (ok){
                            q.push({f-1,g});
                            d[f-1][g]=1;
                        }
                    }
                    if (g+1!=y){
                        bool ok=true;
                        if (d[f][g+1]==1) ok=false;
                        rep(k,n){
                            if (f>=l[k] && f<r[k] && (g+1==b[k] || g+1==t[k])) ok=false;
                        }
                        if (ok){
                            q.push({f,g+1});
                            d[f][g+1]=1;
                        }
                    }
                    if (g-1!=-1){
                        bool ok=true;
                        if (d[f][g-1]==1) ok=false;
                        rep(k,n){
                            if (f>=l[k] && f<r[k] && (g==b[k] || g==t[k])) ok=false;
                        }
                        if (ok){
                            q.push({f,g-1});
                            d[f][g-1]=1;
                        }
                    }
                }
            }
        }
        cout << ans << endl;
    }
}
accuracy: 1
time_ms: 290
memory_kb: 3136
final_rank: 18

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

using P = pair<int,int>;

int main() {
  
  ios::sync_with_stdio(false);
  cin.tie(0);
  
  vector<int> di = {1,0,-1,0};
  vector<int> dj = {0,1,0,-1};
  int n;
  cin >> n;
  while (n != 0) {
    vector<int> l(n),t(n),r(n),b(n);
    for (int i=0;i<n;i++) {
      cin >> l[i] >> t[i] >> r[i] >> b[i];
    }
    vector<int> xs;
    vector<int> ys;
    for (int i=0;i<n;i++) {
      xs.emplace_back(l[i]);
      xs.emplace_back(r[i]);
      ys.emplace_back(t[i]);
      ys.emplace_back(b[i]);
    }
    xs.emplace_back(-100);
    xs.emplace_back(1e7);
    ys.emplace_back(-100);
    ys.emplace_back(1e7);
    sort(xs.begin(),xs.end());
    sort(ys.begin(),ys.end());
    auto itx = unique(xs.begin(),xs.end());
    auto ity = unique(ys.begin(),ys.end());
    xs.erase(itx,xs.end());
    ys.erase(ity,ys.end());
    int nx = xs.size();
    int ny = ys.size();
    vector<vector<long long>> maps(nx-1,vector<long long>(ny-1,0));
    for (int i=0;i<n;i++) {
      for (int j=0;j<nx-1;j++) {
        for (int k=0;k<ny-1;k++) {
          if (xs[j] >= l[i] && r[i] >= xs[j+1] && ys[k] >= b[i] && t[i] >= ys[k+1]) {
            maps[j][k] += 1LL<<i;
          }
        }
      }
    }
    vector<vector<bool>> used(nx-1,vector<bool>(ny-1,false));
    int ans = 0;
    for (int i=0;i<nx-1;i++) {
      for (int j=0;j<ny-1;j++) {
        if (used[i][j]) continue;
        ans++;
        queue<P> q;
        q.push(P(i,j));
        used[i][j] = true;
        while (!q.empty()) {
          P np = q.front();
          q.pop();
          int ni = np.first;
          int nj = np.second;
          //cout << maps[ni][nj] << endl;
          for (int k=0;k<4;k++) {
            int toi = ni+di[k];
            int toj = nj+dj[k];
            if (toi < 0 || toi >= nx-1 || toj < 0 || toj >= ny-1) {
              continue;
            }
            if (maps[toi][toj] != maps[ni][nj]) continue;
            if (used[toi][toj]) continue;
            used[toi][toj] = true;
            q.push(P(toi,toj));
          }
        }
      }
    }
    cout << ans << endl;
    cin >> n;
  }
}
accuracy: 1
time_ms: 60
memory_kb: 3496
final_rank: 9

code_snippet: #define rep(i, n) for(int i=0; i<(n); ++i)
#define rrep(i, n) for(int i=(n-1); i>=0; --i)
#define rep2(i, s, n) for(int i=s; i<(n); ++i)
#define ALL(v) (v).begin(), (v).end()
#define memr(dp, val) memset(dp, val, sizeof(dp))
#define fi first
#define se second
template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; }
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; }
#include <bits/stdc++.h>
using namespace std;
template<typename T>
using min_priority_queue = priority_queue<T, vector<T>, greater<T> >;
typedef long long ll;
const int INTINF = INT_MAX >> 1;
static const ll LLINF = (LLONG_MAX >> 1);

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

int mx, my;

int n;
int l[51], t[51], r[51], b[51];

set<int> s[501][501];
bool used[501][501];

bool input(){

    cin >> n;
    if(!n) return false;
    set<int> xs, ys;
    xs.insert(0);
    xs.insert(1000000);
    ys.insert(0);
    ys.insert(1000000);
    map<int, int> xcomp, ycomp;
    rep(i, n) {
        cin >> l[i] >> t[i] >> r[i] >> b[i];
        xs.insert(l[i]);
        xs.insert(r[i]);
        ys.insert(t[i]);
        ys.insert(b[i]);
    }

    int cnt = 1;
    int bef = -1;
    for(int x : xs) {
        xcomp[x] = cnt;
        cnt++;
        bef = x;
    }
    bef = -1;
    cnt = 1;
    for(int y : ys) {
        ycomp[y] = cnt;
        cnt++;
        bef = y;
    }

    rep(i, n){
        l[i] = xcomp[l[i]];
        r[i] = xcomp[r[i]];
        t[i] = ycomp[t[i]];
        b[i] = ycomp[b[i]];
    }
    mx = xcomp[1000000] + 2;
    my = ycomp[1000000] + 2;

	return true;
}

int main(){
    std::cout << std::fixed << std::setprecision(15);

    while(input()){
        rep(i, my){
            rep(j, mx){
                s[i][j].clear();
            }
        }

        rep(i, n){
            rep(j, r[i] - l[i]){
                rep(k, t[i] - b[i]){
                    s[b[i] + k][l[i] + j].insert(i);
                }
            }
        }

        memr(used, 0);
        int ans = 0;
        rep(i, my){
            rep(j, mx){
                if(!used[i][j]){
                    ans++;
                    queue<pair<int, int> > q;
                    q.push({j, i});
                    used[i][j] = true;
                    while(q.size()){
                        auto f = q.front(); q.pop();
                        rep(k, 4){
                            int nx = f.fi + dx[k];
                            int ny = f.se + dy[k];
                            if(nx < 0 || nx >= mx) continue;
                            if(ny < 0 || ny >= my) continue;
                            if(used[ny][nx]) continue;
                            if(s[ny][nx] != s[f.se][f.fi]) continue;

                            used[ny][nx] = true;
                            q.push({nx, ny});
                        }
                    }
                }
            }
        }
        cout << ans << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 460
memory_kb: 22960
final_rank: 19

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

using ll = long long;
vector<int> dx = {1, 0, -1, 0}, dy = {0, 1, 0, -1};

// 座標圧縮
map<ll, int> compress(const vector<ll> &x) {
  map<ll, int> comp;
  for (int i = 0; i < x.size(); i++) comp[x.at(i)] = 1;
  int i = 0;
  for (auto it = comp.begin(); it != comp.end(); it++, i++) it->second = i;
  return comp;
}

void bfs(vector<vector<bool>> &dp, int si, int sj) {
  dp[si][sj] = true;
  queue<pair<int, int>> q;
  q.push(make_pair(si, sj));
  while (!q.empty()) {
    pair<int, int> p = q.front();
    q.pop();
    for (int i = 0; i < 4; i++) {
      int ni = p.first + dx[i], nj = p.second + dy[i];
      if (0 <= ni && ni < dp.size() && 0 <= nj && nj < dp[0].size() && !dp[ni][nj]) {
        dp[ni][nj] = true;
        q.push(make_pair(ni, nj));
      }
    }
  }
}

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

  while (true) {
    int n;
    cin >> n;
    if (n == 0) return 0;

    vector<ll> l(n), t(n), r(n), b(n), x, y;
    for (int i = 0; i < n; i++) {
      cin >> l[i] >> t[i] >> r[i] >> b[i];
      x.emplace_back(l[i]);
      x.emplace_back(r[i]);
      y.emplace_back(t[i]);
      y.emplace_back(b[i]);
    }
    x.emplace_back(-10);
    x.emplace_back(10000000);
    y.emplace_back(-10);
    y.emplace_back(10000000);

    map<ll, int> mpx = compress(x), mpy = compress(y);

    vector<vector<bool>> dp((int) mpx.size() * 3, vector<bool>((int) mpy.size() * 3, false));
    for (int i = 0; i < n; i++) {
      for (int ii = mpx[l[i]] * 3 + 1; ii <= mpx[r[i]] * 3 + 1; ii++) {
        dp[ii][mpy[b[i]] * 3 + 1] = true;
        dp[ii][mpy[t[i]] * 3 + 1] = true;
      }
      for (int jj = mpy[b[i]] * 3 + 1; jj <= mpy[t[i]] * 3 + 1; jj++) {
        dp[mpx[l[i]] * 3 + 1][jj] = true;
        dp[mpx[r[i]] * 3 + 1][jj] = true;
      }
    }

    int ans = 0;
    for (int i = 0; i < dp.size(); i++) {
      for (int j = 0; j < dp[0].size(); j++) {
        if (!dp[i][j]) {
          bfs(dp, i, j);
          ans++;
        }
      }
    }

    cout << ans << '\n';
  }
}
accuracy: 1
time_ms: 140
memory_kb: 3428
final_rank: 14

code_snippet: // #include "atcoder/all"
#include <iostream> // cout, endl, cin
#include <string> // string, to_string, stoi
#include <vector> // vector
#include <algorithm> // min, max, swap, sort, reverse, lower_bound, upper_bound
#include <utility> // pair, make_pair
#include <tuple> // tuple, make_tuple
#include <cstdint> // int64_t, int*_t
#include <cstdio> // printf
#include <map> // map
#include <queue> // queue, priority_queue
#include <set> // set
#include <stack> // stack
#include <deque> // deque
#include <unordered_map> // unordered_map
#include <unordered_set> // unordered_set
#include <bitset> // bitset
#include <cctype> // isupper, islower, isdigit, toupper, tolower
#include <iomanip> // setprecision
#include <complex> // complex
#include <math.h>
#include <functional>
#include <cassert>
using namespace std;
// using namespace atcoder;
using ll = long long;
using P = pair<ll,ll>;
constexpr ll INF = 1e15;
constexpr ll LLMAX = 9223372036854775807;
constexpr int inf = 1e9;
// constexpr ll mod = 1000000007;
constexpr ll mod = 998244353;
// 右下左上
const int dx[8] = {1, 0, -1, 0,1,1,-1,-1};
const int dy[8] = {0, 1, 0, -1,1,-1,1,-1};
template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; }
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; }
#define eol "\n"
// ---------------------------------------------------------------------------

template<typename T>
struct Compress {
	vector<T> v;
	Compress() {}
	Compress(vector<T> _v) {
		build(_v);
	}
 
	void build(vector<T> _v) {
		v = _v;
		sort(v.begin(), v.end());
		v.erase(unique(v.begin(), v.end()), v.end());
	}
	int get(T x) {
		return lower_bound(v.begin(), v.end(), x) - v.begin();
	}
 
	T& operator[](int i) { return v[i]; }
 
 
	int size() {
		return (int)v.size();
	}
};


struct UnionFind {
    vector<int> par, w;

    UnionFind(int n) : par(n, -1), w(n, 0) { }
    void init(int n) { par.assign(n, -1); w.assign(n, 0); }

    int root(int x) {
        if (par[x] < 0) return x;
        else return par[x] = root(par[x]);
    }

    bool issame(int x, int y) {
        return root(x) == root(y);
    }

    bool merge(int x, int y) {
        x = root(x); y = root(y);
        if (x == y) {
            ++w[x];
            return false;
        }
        if (par[x] > par[y]) swap(x, y); // merge technique
        par[x] += par[y];
        par[y] = x;
        w[x] += w[y];
        ++w[x];
        return true;
    }

    int size(int x) {
        return -par[root(x)];
    }

    int wei(int x) {
        return w[root(x)];
    }
};


bool solve(){
  int N;
  cin >> N;
  if(N == 0) return false;
  vector<int> X,Y;
  vector<int> lx(N),ly(N),rx(N),ry(N);
  for(int i=0; i<N; i++){
    cin >> lx[i] >> ry[i] >> rx[i] >> ly[i];
    X.emplace_back(lx[i]);
    X.emplace_back(rx[i]);
    Y.emplace_back(ly[i]);
    Y.emplace_back(ry[i]);
  }
  X.emplace_back(-1);
  X.emplace_back(inf);
  Y.emplace_back(-1);
  Y.emplace_back(inf);
  Compress<int> CX(X),CY(Y);
  vector<vector<ll>> G(CX.size()+1,vector<ll>(CY.size()+1));
  for(int i=0; i<N; i++){
    for(int x=CX.get(lx[i]); x<CX.get(rx[i]); x++){
      for(int y=CY.get(ly[i]); y<CY.get(ry[i]); y++){
        G[x][y] += (1LL<<i);
      }
    }
  }
  // for(int i=0; i<CX.size(); i++){
  //   for(int j=0; j<CY.size(); j++){
  //     cout << G[i][j] << " \n"[j+1==CY.size()];
  //   }
  // }
  int ans = 0;
  vector<vector<int>> used(CX.size(),vector<int>(CY.size(),0));
  for(int i=0; i<CX.size(); i++){
    for(int j=0; j<CY.size(); j++){
      if(used[i][j] != 0) continue;
      ans++;
      queue<P> que;
      que.emplace(i,j);
      used[i][j] = ans;
      while(que.size()){
        int y = que.front().first;
        int x = que.front().second;
        que.pop();
        for(int k=0; k<4; k++){
          int ny = y + dy[k];
          int nx = x + dx[k];
          if(ny<0 || ny>=CX.size() || nx<0 || nx>=CY.size()) continue;
          if(G[y][x] != G[ny][nx]) continue;
          if(used[ny][nx] != 0) continue;
          used[ny][nx] = ans;
          que.emplace(ny,nx);
        }
      }
    }
  }
  cout << ans << endl;
  return true;
}

int main(){
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  while(solve());
  return 0;
}
accuracy: 1
time_ms: 50
memory_kb: 3428
final_rank: 6

code_snippet: #include<bits/stdc++.h>
using namespace std;
using T = tuple<int,int,int,int>;
const int MAX = 500;

map<int64_t,int64_t> mx;
map<int64_t,int64_t> my;

set<int> sum[MAX][MAX];
void init(){
  for(int i=0; i<MAX; i++){
    for(int j=0; j<MAX; j++){
      sum[i][j].clear();
    }
  }
}

//一次元座標圧縮
map<int64_t, int64_t> compression(vector<int64_t> V){
  map<int64_t, int64_t> ret;
  int64_t cnt = 0;
  sort(V.begin(),V.end());
  for(int i=0; i<V.size(); i++){
    if(!ret.count(V[i])){
      ret[V[i]] = cnt;
      cnt++;
    }
  }
  return ret;
}

//UnionFind
int n = 500*500;
vector<int> par(n);
vector<int> Size(n);

void init_union(int n){
  for(int i=0; i<n; i++){
    par.at(i) = i;
    Size.at(i) = 1;
  }
}

int root(int x){
  if(par.at(x) == x){
    return x;
  }
  else{
    return par.at(x) = root(par.at(x));
  }
}

bool same(int x, int y){
  return root(x) == root(y);
}

void unite(int x, int y){
  x = root(x);
  y = root(y);
  if(x == y){
    return;
  }
  if (Size.at(x) < Size.at(y)){
    swap(x, y);
  }
  Size.at(x) += Size.at(y);
  par.at(y) = x;
}

int Size_x(int x){
  return Size.at(root(x));
}

void solve(int N){
  init();
  vector<T> vec(N);
  vector<int64_t> X = {-1000000000, 1000000000};
  vector<int64_t> Y = {-1000000000, 1000000000};
  for(int i=0; i<N; i++){
    int x1, y1, x2, y2;
    cin >> x1 >> y2 >> x2 >> y1;
    x2--; y2--;
    vec[i] = {x1,y1,x2,y2};
    for(int j=-1; j<=1; j++){
      X.push_back(x1+j);
      X.push_back(x2+j);
      Y.push_back(y1+j);
      Y.push_back(y2+j);
    }
  }
  mx = compression(X);
  my = compression(Y);
  for(int i=0; i<N; i++){
    auto[x1,y1,x2,y2] = vec[i];
    for(auto itr = mx.begin(); itr != mx.end(); itr++){
      int x = itr->first;
      for(auto itr2 = my.begin(); itr2 != my.end(); itr2++){
        int y = itr2->first;
        if(x1 <= x && x <= x2 && y1 <= y && y <= y2){
          sum[itr->second][itr2->second].insert(i);
        }
      }
    }
  }
  init_union(n);
  vector<int> dx = {0,1,0,-1};
  vector<int> dy = {1,0,-1,0};
  for(int i=0; i<MAX; i++){
    for(int j=0; j<MAX; j++){
      for(int k=0; k<4; k++){
        if(0 <= i+dx[k] && i+dx[k] < MAX-1 && 0 <= j+dy[k] && j+dy[k] < MAX-1){
          if(sum[i][j] == sum[i+dx[k]][j+dy[k]]){
            unite(i*MAX+j, (i+dx[k])*MAX + j+dy[k]);
          }
        }
      }
    }
  }
  int ans = 0;
  for(int i=0; i<X.size(); i++){
    for(int j=0; j<Y.size(); j++){
      if(root(i*MAX+j) == i*MAX+j){
        ans++;
      }
    }
  }
  cout << ans << endl;
  
  /*for(int i=0; i<X.size(); i++){
    for(int j=0; j<Y.size(); j++){
      cout << num[i][j] << " ";
    }
    cout << endl;
  }*/
}

int main(){
  while(true){
    int N;
    cin >> N;
    if(N == 0){
      break;
    }
    solve(N);
    //break;
  }
}
accuracy: 1
time_ms: 6120
memory_kb: 87764
final_rank: 20

code_snippet: #line 1 "main.cpp"
#pragma region Macros
#include <bits/stdc++.h>
using namespace std;
template <class T> inline bool chmax(T &a, T b) {
    if(a < b) {
        a = b;
        return 1;
    }
    return 0;
}
template <class T> inline bool chmin(T &a, T b) {
    if(a > b) {
        a = b;
        return 1;
    }
    return 0;
}
#ifdef DEBUG
template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
    os << '(' << p.first << ',' << p.second << ')';
    return os;
}
template <class T> ostream &operator<<(ostream &os, const vector<T> &v) {
    os << '{';
    for(int i = 0; i < (int)v.size(); i++) {
        if(i) { os << ','; }
        os << v[i];
    }
    os << '}';
    return os;
}
void debugg() { cerr << endl; }
template <class T, class... Args>
void debugg(const T &x, const Args &... args) {
    cerr << " " << x;
    debugg(args...);
}
#define debug(...)                                                             \
    cerr << __LINE__ << " [" << #__VA_ARGS__ << "]: ", debugg(__VA_ARGS__)
#define dump(x) cerr << __LINE__ << " " << #x << " = " << (x) << endl
#else
#define debug(...) (void(0))
#define dump(x) (void(0))
#endif

struct Setup {
    Setup() {
        cin.tie(0);
        ios::sync_with_stdio(false);
        cout << fixed << setprecision(15);
    }
} __Setup;

using ll = long long;
#define ALL(v) (v).begin(), (v).end()
#define RALL(v) (v).rbegin(), (v).rend()
#define FOR(i, a, b) for(int i = (a); i < int(b); i++)
#define REP(i, n) FOR(i, 0, n)
const int INF = 1 << 30;
const ll LLINF = 1LL << 60;
constexpr int MOD = 1000000007;

void Case(int i) { cout << "Case #" << i << ": "; }
int popcount(int x) { return __builtin_popcount(x); }
ll popcount(ll x) { return __builtin_popcountll(x); }
#pragma endregion Macros

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

#line 1 "/home/siro53/kyo-pro/compro_library/data_structure/compress.hpp"
template <typename T> struct Compress {
    vector<T> v;
    Compress() {}
    Compress(vector<T> vv) : v(vv) {
        sort(ALL(v));
        v.erase(unique(ALL(v)), end(v));
    }
    void build(vector<T> vv) {
        v = vv;
        sort(ALL(v));
        v.erase(unique(ALL(v)), end(v));
    }
    int get(T x) { return (int)(lower_bound(ALL(v), x) - v.begin()); }
    T &operator[](int i) { return v[i]; }
    size_t size() { return v.size(); }
};
#line 1 "/home/siro53/kyo-pro/compro_library/graph/dsu.hpp"
struct UnionFind {
    vector<int> par;

    UnionFind(int n) : par(n, -1) {}
    void init(int n) { par.assign(n, -1); }

    int root(int x) {
        if(par[x] < 0)
            return x;
        else
            return par[x] = root(par[x]);
    }

    bool issame(int x, int y) { return root(x) == root(y); }

    bool merge(int x, int y) {
        x = root(x);
        y = root(y);
        if(x == y)
            return false;
        if(par[x] > par[y])
            swap(x, y); // merge technique
        par[x] += par[y];
        par[y] = x;
        return true;
    }

    int size(int x) { return -par[root(x)]; }
};
#line 74 "main.cpp"

using R = array<int, 4>;

bool solve() {
    int N;
    cin >> N;
    if(N == 0) return false;
    vector<R> recs(N);
    Compress<int> comp_x, comp_y;
    {
        vector<int> vx = {-1, 1000001}, vy = {-1, 1000001};
        REP(i, N) {
            int x1, y1, x2, y2;
            cin >> x1 >> y2 >> x2 >> y1;
            vx.push_back(x1);
            vy.push_back(y1);
            vx.push_back(x2);
            vy.push_back(y2);
            recs[i] = {x1, y1, x2, y2};
        }
        comp_x.build(vx); comp_y.build(vy);
        REP(i, N) {
            recs[i][0] = comp_x.get(recs[i][0]) * 2;
            recs[i][1] = comp_y.get(recs[i][1]) * 2;
            recs[i][2] = comp_x.get(recs[i][2]) * 2;
            recs[i][3] = comp_y.get(recs[i][3]) * 2;
        }
    }
    int Lx = comp_x.size() * 2;
    int Ly = comp_y.size() * 2;
    vector G(Lx, vector<int>(Ly, 0));
    REP(i, N) {
        auto [x1, y1, x2, y2] = recs[i];
        FOR(y, y1, y2+1) G[x1][y] = G[x2][y] = 1;
        FOR(x, x1, x2+1) G[x][y1] = G[x][y2] = 1;
    }
    UnionFind uf(Lx*Ly);

    REP(i, Lx) REP(j, Ly) {
        if(G[i][j]) continue;
        REP(dir, 4) {
            int ni = i + dx[dir], nj = j + dy[dir];
            if(ni < 0 or ni >= Lx or nj < 0 or nj >= Ly) continue;
            if(G[ni][nj]) continue;
            uf.merge(i*Ly + j, ni*Ly + nj);
        }
    }
    set<int> se;
    REP(i, Lx) REP(j, Ly) {
        if(G[i][j]) continue;
        se.insert(uf.root(i*Ly + j));
    }
    cout << se.size() << endl;

    return true;
}

int main() {
    while(solve());
}
accuracy: 1
time_ms: 100
memory_kb: 3780
final_rank: 12

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

using ll = long long int;
using ull = unsigned long long int;
using P = pair<int, int>;
using P3 = pair<P,int>;
using PP = pair<P, P>;
constexpr int INF32 = 1 << 30;
constexpr ll INF64 = 1LL << 60;
constexpr ll MOD = 1000000007;
// constexpr ll MOD = 998244353;
constexpr int di[] = {0, 1, 0, -1};
constexpr int dj[] = {1, 0, -1, 0};
constexpr int di8[] = {0, 1, 1, 1, 0, -1, -1, -1};
constexpr int dj8[] = {1, 1, 0, -1, -1, -1, 0, 1};
constexpr double EPS = 1e-9;
const double PI = acos(-1);

#define ALL(v) (v).begin(),(v).end()
#define REP(i,n) for(int i=0,i_len=n; i<i_len; ++i)

template<typename T1,typename T2> bool chmax(T1 &a, T2 b) { if (a<b) { a=b; return 1; } return 0; }
template<typename T1,typename T2> bool chmin(T1 &a, T2 b) { if (b<a) { a=b; return 1; } return 0; }

struct UnionFindTree {
    vector<int> par;
    vector<int> rank;
    vector<int> siz;
    int N;

    void init(int n) {
        par.resize(n);
        rank.resize(n);
        siz.resize(n);
        for (int i = 0; i < n; i++) {
            par[i] = i;
            rank[i] = 0;
            siz[i] = 1;
            N = n;
        }
    }
    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 (rank[x] < rank[y]) swap(x, y);
        if (rank[x] == rank[y]) rank[x]++;
        par[y] = x;
        siz[x] += siz[y];
        N--;
    }
    bool is_same(int x, int y) {
        return find(x) == find(y);
    }
    int size(int x) {
        x = find(x);
        return siz[x];
    }
};

map<int,int> compress(vector<int> x){
    auto v = x;
    sort(ALL(v));
    v.erase(unique(ALL(v)),v.end());
    map<int,int> ord;
    for(int i=0;i<v.size();i++) ord[v[i]] = i;
    return ord;
}

int solve(){
    int n;
    cin >> n;
    if(n == 0) return 1;
    vector<int> xs, ys, l(n), t(n), r(n), b(n);
    REP(i,n){
        cin >> l[i] >> t[i] >> r[i] >> b[i];
        xs.push_back(l[i]);
        xs.push_back(r[i]);
        ys.push_back(t[i]);
        ys.push_back(b[i]);
    }
    auto xord = compress(xs);
    auto yord = compress(ys);
    int m = max(xord.size(), yord.size()) + 1;
    REP(i,n){
        l[i] = xord[l[i]]+1;
        r[i] = xord[r[i]]+1;
        t[i] = yord[t[i]]+1;
        b[i] = yord[b[i]]+1;
    }
    vector<vector<ll> > a(m+1, vector<ll>(m+1));
    REP(i,n){
        a[l[i]][b[i]] |= 1LL<<i;
        a[l[i]][t[i]] |= 1LL<<i;
        a[r[i]][b[i]] |= 1LL<<i;
        a[r[i]][t[i]] |= 1LL<<i;
    }
    REP(i,m+1) REP(j,m) a[i][j+1] ^= a[i][j];
    REP(i,m) REP(j,m+1) a[i+1][j] ^= a[i][j];
    UnionFindTree uf;
    uf.init((m+1)*(m+1));
    REP(i,m+1) REP(j,m+1){
        if(i<m && a[i][j]==a[i+1][j]) uf.unite(i*(m+1)+j, (i+1)*(m+1)+j);
        if(j<m && a[i][j]==a[i][j+1]) uf.unite(i*(m+1)+j, i*(m+1)+j+1);
    }
    cout << uf.N << endl;
    return 0;
}

int main(){
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    // solve();
    // int T; cin >> T; REP(t,T) solve();
    while(!solve());
    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 3328
final_rank: 1