#include <bits/stdc++.h>

#define REP(i, n) for(decltype(n) i = 0; i < n; i++)

#define ALL(c)   c.begin(), c.end()
#define SORT(c)  std::sort(ALL(c))
#define RSORT(c) std::sort(ALL(c), std::greater<decltype(c)::value_type>())

using namespace std;
using ll = long long;

const int MOD  = (int)1e9 + 7;
const int INF  = (int)1e9 + 1;
const ll  LINF = (long long)1e18 + 1;

class UnionFind {
    using ll = long long;
public:
    struct Node {
        ll parent, weight, size, rank;
        Node(const ll& _parent = 0,
             const ll& _weight = 0,
             const ll& _size   = 1,
             const ll& _rank   = 0) :
            parent(_parent),
            weight(_weight),
            size(_size),
            rank(_rank) { }
    };

    explicit UnionFind(const ll& num_node) {
        node_.reserve(num_node);
        for(ll i = 0; i < num_node; i++) {
            node_.emplace_back(i);
        }
    }

    const std::vector<Node>& getNode() const {
        return node_;
    }

    ll searchAndZipRoot(const ll& x) {
        if(node_[x].parent == x) {
            return x;
        }
        else {
            auto r = searchAndZipRoot(node_[x].parent);
            node_[x].weight += node_[node_[x].parent].weight;
            node_[x].parent  = r;
            return r;
        }
    }

    void unite(const ll& x,
               const ll& y,
               const ll& weight = 0) {
        auto rx = searchAndZipRoot(x);
        auto ry = searchAndZipRoot(y);
        if(rx != ry) {
            auto yw = weight + calcWeight(x) - calcWeight(y);
            if(node_[rx].rank < node_[ry].rank) {
                std::swap(rx, ry);
                yw *= -1;
            }
            node_[ry].parent  = rx;
            node_[ry].weight  = yw;
            node_[rx].size   += node_[ry].size;
            if(node_[rx].rank == node_[ry].rank) {
                node_[rx].rank++;
            }
        }
    }

    ll calcWeight(const ll& x) {
        searchAndZipRoot(x);
        return node_[x].weight;
    }

    ll calcDiff(const ll& x,
                const ll& y) {
        return std::abs(calcWeight(x) - calcWeight(y));
    }

    ll calcSize(const ll& x) {
        return node_[searchAndZipRoot(x)].size;
    }

    template<class... A>
    bool checkWhetherRootIsSame(const A&... nodes) {
        auto node_list = std::initializer_list<ll>{nodes...};
        if(node_list.size() < 2) return false;
        auto v = searchAndZipRoot(*node_list.begin());
        for(size_t i = 1; i < node_list.size(); i++) {
            if(v != searchAndZipRoot(*(node_list.begin() + i))) return false;
        }
        return true;
    }

private:
    std::vector<Node> node_;
};

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

    int N, K, L;
    std::cin >> N >> K >> L;

    UnionFind road(N), tr(N);
    REP(i, K) {
        int p, q;
        std::cin >> p >> q;
        road.unite(p - 1, q - 1);
    }
    REP(i, L) {
        int r, s;
        std::cin >> r >> s;
        tr.unite(r - 1, s - 1);
    }

    map<pair<int, int>, int> map;
    REP(i, N) {
        auto p = make_pair(road.searchAndZipRoot(i), tr.searchAndZipRoot(i));
        auto itr = map.find(p);
        if(itr != map.end()) {
            itr->second++;
        }
        else {
            map.emplace(p, 1);
        }
    }

    REP(i, N) {
        std::cout << map[make_pair(road.searchAndZipRoot(i), tr.searchAndZipRoot(i))] << " ";
    }
    std::cout << std::endl;

    return 0;
}


Measured memory_bytes: 24064