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

template <typename T>
class BinaryIndexedTree
{
    std::vector<T> arr;
    const std::size_t size;
    const std::function<T(const T, const T)> operation;
    const T initial_value;

    void initialize_array()
    {
        this->arr = std::vector<T>(this->size, this->initial_value);
    }

public:
    BinaryIndexedTree(const std::size_t N, std::function<T(const T, const T)> func, T init) : size(N + 1), operation(func), initial_value(init)
    {
        initialize_array();
    }

    void update(const std::size_t idx, const T value)
    {
        long long idxll = (long long)idx;
        while (idxll <= (long long)this->size)
        {
            this->arr[idxll] = this->operation(this->arr[idxll], value);
            idxll += (idxll & -idxll);
        }
    }

    T query(const std::size_t idx)
    {
        T ret = this->initial_value;
        long long idxll = (long long)idx;
        while (idxll > 0)
        {
            ret = this->operation(ret, this->arr[idxll]);
            idxll -= (idxll & -idxll);
        }
        return ret;
    }
};

class UnionFind
{
    std::vector<std::size_t> root;
    const std::size_t maximum_size;

public:
    UnionFind(const std::size_t N) : maximum_size(N + 5)
    {
        this->root = std::vector<std::size_t>(N + 1, this->maximum_size);
    }

    std::size_t find_root(const std::size_t A)
    {
        if (this->root[A] >= this->maximum_size)
        {
            return A;
        }
        this->root[A] = this->find_root(this->root[A]);
        return this->root[A];
    }

    std::size_t size(const std::size_t A)
    {
        return this->root[this->find_root(A)] - this->maximum_size + 1;
    }

    bool unite(const std::size_t A, const std::size_t B)
    {
        std::size_t rootA = find_root(A);
        std::size_t rootB = find_root(B);
        if (rootA == rootB)
        {
            return false;
        }

        if (this->size(rootA) < this->size(rootB))
        {
            std::swap(rootA, rootB);
        }

        this->root[rootA] += this->size(rootB);
        this->root[rootB] = rootA;

        return true;
    }

    bool has_same_root(const std::size_t A, const std::size_t B)
    {
        return this->find_root(A) == this->find_root(B);
    }
};

void f(vector<int> &x, vector<int> &y, UnionFind &uf)
{
    size_t n = x.size();
    BinaryIndexedTree<int> bit(
        n + 5, [](int a, int b) { return max(a, b); }, INT_MIN);

    vector<pair<int, size_t>> x_with_index(n);
    for (size_t i = 0; i < n; i++)
    {
        x_with_index[i] = make_pair(x[i], i);
    }
    sort(x_with_index.begin(), x_with_index.end());

    priority_queue<pair<int, size_t>, vector<pair<int, size_t>>, greater<pair<int, size_t>>> q;
    for (size_t i = 0; i < n; i++)
    {
        size_t index = x_with_index[i].second;
        if (bit.query(y[index]) >= 0)
        {
            uf.unite(index, bit.query(y[index]));
        }

        while (!q.empty())
        {
            if (q.top().first < y[index])
            {
                uf.unite(index, q.top().second);
                q.pop();
            }
            else
            {
                break;
            }
        }

        q.push(make_pair(y[index], index));
        bit.update(y[index], index);
    }
}

int main()
{
    size_t N;
    cin >> N;

    vector<int> x(N);
    vector<int> y(N);
    for (size_t i = 0; i < N; i++)
    {
        cin >> x[i] >> y[i];
    }

    UnionFind uf(N);

    f(x, y, uf);
    f(y, x, uf);

    for (size_t i = 0; i < N; i++)
    {
        x[i] = N - x[i] + 1;
        y[i] = N - y[i] + 1;
    }
    f(x, y, uf);
    f(y, x, uf);

    for (size_t i = 0; i < N; i++)
    {
        cout << uf.size(i) << endl;
    }
}


Measured memory_bytes: 11824