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

void print() { cout << endl; }
template <typename Head, typename... Tail>
void print(Head head, Tail... tail) {
    int size = sizeof...(Tail);
    cout << head;
    if (size > 0) {
        cout << " ";
    }
    print(tail...);
}

void print0() {}
template <typename Head, typename... Tail>
void print0(Head head, Tail... tail) {
    cout << head;
    print0(tail...);
}

struct xstruct {
    int val;
};
bool operator<=(const xstruct& lhs, const xstruct& rhs) {
    return lhs.val <= rhs.val;
}
bool operator<(const xstruct& lhs, const xstruct& rhs) {
    return lhs.val < rhs.val;
}
bool operator>=(const xstruct& lhs, const xstruct& rhs) {
    return lhs.val >= rhs.val;
}
bool operator>(const xstruct& lhs, const xstruct& rhs) {
    return lhs.val > rhs.val;
}
bool operator==(const xstruct& lhs, const xstruct& rhs) {
    return lhs.val == rhs.val;
}
bool operator!=(const xstruct& lhs, const xstruct& rhs) {
    return lhs.val != rhs.val;
}
class xunionfind {
   public:
    map<xstruct, xstruct> partition;
    map<xstruct, uint64_t> rank;

    void append(xstruct x) {
        partition[x] = x;
        rank[x] = 0;
    }
    xstruct find(xstruct x) {
        if (partition[x] == x) {
            return x;
        } else {
            partition[x] = find(partition[x]);
            return partition[x];
        }
    }
    void unite(xstruct x, xstruct y) {
        x = find(x);
        y = find(y);
        if (x == y) {
            return;
        }
        if (rank[x] < rank[y]) {
            partition[x] = y;
        } else {
            partition[y] = x;
            if (rank[x] == rank[y]) {
                rank[x]++;
            }
        }
    }
    bool same(xstruct x, xstruct y) {
        return find(x) == find(y);
    }
};

class iunionfind {
   public:
    vector<uint64_t> partition;
    vector<uint64_t> rank;

    iunionfind(uint64_t n) {
        partition.resize(n);
        rank.resize(n);
        for (uint64_t x = 0; x < n; x++) {
            partition[x] = x;
            rank[x] = 0;
        }
    }
    uint64_t find(uint64_t x) {
        if (partition[x] == x) {
            return x;
        } else {
            partition[x] = find(partition[x]);
            return partition[x];
        }
    }
    void unite(uint64_t x, uint64_t y) {
        x = find(x);
        y = find(y);
        if (x == y) {
            return;
        }
        if (rank[x] < rank[y]) {
            partition[x] = y;
        } else {
            partition[y] = x;
            if (rank[x] == rank[y]) {
                rank[x]++;
            }
        }
    }
    bool same(uint64_t x, uint64_t y) {
        return find(x) == find(y);
    }
};

int main() {
    uint64_t N, K, L;
    cin >> N;
    cin >> K;
    cin >> L;

    vector<pair<uint64_t, uint64_t>> pq(K);
    for (uint64_t i = 0; i < K; i++) {
        cin >> pq[i].first;
        cin >> pq[i].second;
        pq[i].first--;
        pq[i].second--;
    }

    vector<pair<uint64_t, uint64_t>> rs(L);
    for (uint64_t i = 0; i < L; i++) {
        cin >> rs[i].first;
        cin >> rs[i].second;
        rs[i].first--;
        rs[i].second--;
    }

    auto rail = new iunionfind(N);
    auto road = new iunionfind(N);
    for (uint64_t i = 0; i < K; i++) {
        road->unite(pq[i].first, pq[i].second);
    }
    for (uint64_t i = 0; i < L; i++) {
        rail->unite(rs[i].first, rs[i].second);
    }

    map<pair<uint64_t, uint64_t>, uint64_t> cnts;
    for (uint64_t i = 0; i < N; i++) {
        auto p = pair<uint64_t, uint64_t>{road->find(i), rail->find(i)};
        if (cnts.count(p) == 0) {
            cnts[p] = 0;
        }
        cnts[p]++;
    }
    for (uint64_t i = 0; i < N; i++) {
        auto p = pair<uint64_t, uint64_t>{road->find(i), rail->find(i)};
        if (i > 0) {
            cout << " ";
        }
        cout << cnts[p];
    }
    cout << endl;
}


Measured memory_bytes: 23508