#include <bits/stdc++.h>
#include <atcoder/all>
using namespace atcoder;
using namespace std;

#pragma region Macros
using ll = long long;
#define int ll
using pii = pair<int, int>;
using tiii = tuple<int, int, int>;
template<class T = ll> using V = vector<T>;
template<class T = ll> using VV = V<V<T>>;
#define IOS\
    ios::sync_with_stdio(false);\
    cin.tie(0);\
    cout.tie(0);
#define FOR(i,l,r) for(ll i=(l);i<(r);++i)
#define REP(i,n) FOR(i,0,n)
#define REPS(i,n) FOR(i,1,n+1)
#define RFOR(i,l,r) for(ll i=(l);i>=(r);--i)
#define RREP(i,n) RFOR(i,n-1,0)
#define RREPS(i,n) RFOR(i,n,1)
#define mp make_pair
#define mt make_tuple
#define pb push_back
#define eb emplace_back
#define all(x) (x).begin(),(x).end()
#define SORT(name) sort(name.begin(), name.end())
#define RSORT(name)\
    SORT(name);\
    reverse(all(name));
#define ZERO(p) memset(p, 0, sizeof(p))
#define MINUS(p) memset(p, -1, sizeof(p))
inline void Yes(bool b = true) {cout << (b ? "Yes" : "No") << '\n';}
inline void YES(bool b = true) {cout << (b ? "YES" : "NO") << '\n';}
template <class T> inline void print(T x){ cout << x << '\n';}
template<typename T1,typename T2> inline void chmin(T1 &a, T2 b){ if(a > b) a = b; }
template<typename T1,typename T2> inline void chmax(T1 &a, T2 b){ if(a < b) a = b; }

const ll LLINF = (1LL<<60);
const int INF = (1LL<<30);
const double DINF = std::numeric_limits<double>::infinity();
#pragma endregion

#if 1
#  define DBG(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
#  define DBG(fmt, ...)
#endif

class UnionFind {
    public:
        UnionFind(){}
        UnionFind(int size) { Init(size); }
        // size: Union-Find で扱いたい要素の数
        void Init(int size) { m_Data.assign(size, -1); }

        // x と y の属する集合を併合
        // 既に一緒な集合内にいるなら false を
        // 新たに併合されたなら true を返す
        bool Unite(int x, int y) {
            x = Find(x), y = Find(y);
            if(x == y) { return (false); }
            if(m_Data[x] > m_Data[y]) { swap(x, y); }
            m_Data[x] += m_Data[y];
            m_Data[y] = x;
            return (true);
        }

        // 要素 k が属する集合の根を返す
        int Find(int k) {
            if(m_Data[k] < 0) { return (k); }
            return (m_Data[k] = Find(m_Data[k]));
        }

        // 要素 k と同じ集合の要素数を返す
        int Size(int k) { return (-m_Data[Find(k)]); }

        // 要素のうち独立しているグループの数 O(NlogN)
        int GetGroupNum() {
            map<int, bool> groups;
            for(int i = 0; i < m_Data.size(); ++i) { groups[Find(i)] = true; }
            return static_cast<int>(groups.size());
        }

    private:
        vector<int> m_Data;
};

template< typename SType>
class SegmentTree
{
    public:
        // 集合の要素 2 つを引数に取リ、その二項演算結果を返す関数
        using Func = function< SType(SType, SType) >;

    public:
        SegmentTree() {}
        SegmentTree(int n, const Func f, const SType &e) { Init(n, f, e); }
        // セグ木を初期化します。
        // サイズは 10^6 くらいまでならいけそう
        // n  : セグ木のサイズ
        // f  : セグ木で判定する関数
        // e : 初期値(単位元)
        void Init(int n, const Func f, const SType &e) {
            m_F = f; m_E = e;
            // 要素数は 2 のべき乗じゃないといけないのでそうする
            m_Size = 1;
            while(m_Size < n) { m_Size <<= 1; }
            m_Seg.assign(2 * m_Size, m_E);
        }

        // k 番目の要素に x をセット (0-indexed)
        void Set(int k, const SType &x) { m_Seg[k + m_Size] = x; }

        // セグ木構築 O(N)
        void Build() {
            for(int k = m_Size - 1; k > 0; k--) {
                // 子ノードに対しての演算結果を親ノードに格納
                m_Seg[k] = m_F(m_Seg[2 * k + 0], m_Seg[2 * k + 1]);
            }
        }

        // k 番目の要素を x に変更する O(log N) (0-indexed)
        // Build 後も利用可能
        void Update(int k, const SType &x) {
            k += m_Size;
            m_Seg[k] = x;
            while(k >>= 1) {
                m_Seg[k] = m_F(m_Seg[2 * k + 0], m_Seg[2 * k + 1]);
            }
        }

        // 区間 [a, b) に対して初期設定した関数をした結果を返す O(log N)
        // 開区間なので b は含まれないので注意
        // 0-indexed
        SType Query(int a, int b) {
            SType l = m_E, r = m_E;
            for(a += m_Size, b += m_Size; a < b; a >>= 1, b >>= 1) {
                if(a & 1) l = m_F(l, m_Seg[a++]);
                if(b & 1) r = m_F(m_Seg[--b], r);
            }
            return m_F(l, r);
        }

        SType operator[](const int &k) const
        {
            return m_Seg[k + m_Size];
        }
    public:
        Func m_F;               // このセグ木で処理する関数（二項演算）
        SType m_E;              // 初期値(単位元)

        int m_Size;             // セグ木の要素数
        vector< SType > m_Seg;  // セグ木本体。一次元で管理する
};

const int MOD = 1000000007;
const int MAX_N = 100010;

int N;
V<tiii> XYi;
SegmentTree<int> seg1, seg2;
UnionFind uf;
V<bool> isUsed;
V<> valToIndY;  // Y 座標からソート後のインデックスへ
V<> indToInd;   // ソート後のインデックスからソート前のインデックスへ

void dfs(int i) {
    if(isUsed[i]) { return; }
    isUsed[i] = true;
    // 自分より右上に行く
    if(i + 1 < N) {
        int res = seg1.Query(i + 1, N);
        if(res > get<1>(XYi[i])) {
            int next_ind = valToIndY[res];
            uf.Unite(get<2>(XYi[i]), indToInd[next_ind]);
            dfs(next_ind);
        }
    }
    // 自分より左下に行く
    {
        int res = seg2.Query(0, i);
        if(res < get<1>(XYi[i])) {
            int next_ind = valToIndY[res];
            uf.Unite(get<2>(XYi[i]), indToInd[next_ind]);
            dfs(next_ind);
        }
    }
}

signed main() {
    IOS;

    cin >> N;
    REP(i, N) {
        int x, y;
        cin >> x >> y;
        XYi.pb(mt(x, y, i));
    }
    SORT(XYi);

    valToIndY.resize(N + 10);
    indToInd.resize(N + 10);
    REP(i, N) {
        int y = get<1>(XYi[i]);
        int ind = get<2>(XYi[i]);
        valToIndY[y] = i;
        indToInd[i] = ind;
    }

    auto Rmq = [](int a, int b) -> int {
        return max(a, b);
    };
    seg1.Init(N, Rmq, -1);
    auto Rmq2 = [](int a, int b) -> int {
        return min(a, b);
    };
    seg2.Init(N, Rmq2, LLINF);
    uf.Init(N);
    REP(i, N) {
        int y = get<1>(XYi[i]);
        seg1.Set(i, y);
        seg2.Set(i, y);
    }
    seg1.Build();
    seg2.Build();

    // bf
    REP(i, N) {
        for(int j = i + 1; j < min(i + 100, N); ++j) {
            int i_y = get<1>(XYi[i]);
            int j_y = get<1>(XYi[j]);
            int i_i = get<2>(XYi[i]);
            int j_i = get<2>(XYi[j]);
            if(i_y < j_y) {
                uf.Unite(i_i, j_i);
            }
        }
    }

    isUsed.assign(N, false);
    REP(i, N) {
        dfs(i);
    }

    REP(i, N) {
        print(uf.Size(i));
    }

    return 0;
}


Measured memory_bytes: 20868