//
//  main.cpp
//

#include <algorithm>
#include <array>
#include <assert.h>
#include <iomanip>
#include <iostream>
#include <limits>
#include <map>
#include <math.h>
#include <memory>
#include <memory>
#include <queue>
#include <random>
#include <set>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <vector>

using namespace std;

using ll = int64_t;
using ull = uint64_t;
constexpr ll LL_MAX = numeric_limits<ll>::max();
constexpr ull ULL_MAX = numeric_limits<ull>::max();

template<typename T>
vector<T> make_vec_nd(T init, ll size) {
	return vector<T>(size, init);
}
template<typename T, typename... Args>
auto make_vec_nd(T init, ll size, Args... rest) {
	auto inner = make_vec_nd(init, rest...);
	return vector<decltype(inner)>(size, inner);
}

#define rep(i, a, b) for (ll i = (a); i < (b); i++)
#define rrep(i, a, b) for (ll i = (a)-1; i >= (b); i--)

struct UnionFind {
    vector<size_t> parent;
    vector<size_t> rank;
    size_t find_parent(size_t x) {
        if (parent[x] == x) {
            return x;
        } else {
            parent[x] = find_parent(parent[x]);
            return parent[x];
        }
    }
    explicit UnionFind(size_t size) {
        parent.resize(size);
        rank.resize(size);
        for (size_t i = 0; i < size; i++) {
            parent[i] = i;
            rank[i] = 0;
        }
    }
    virtual ~UnionFind() {}
    void unite(size_t x, size_t y) {
        size_t px = find_parent(x);
        size_t py = find_parent(y);
        if (px == py) {
            return;
        }
        if (rank[px] < rank[py]) {
            parent[px] = py;
        } else if (rank[px] > rank[py]) {
            parent[py] = px;
        } else {    // rank[px] == rank[py]
            parent[py] = px;
            rank[px]++;
        }
    }
    bool is_same(size_t x, size_t y) {
        return find_parent(x) == find_parent(y);
    }
    unordered_map<size_t, set<size_t>> create_map_parent_to_elements() {
        unordered_map<size_t, set<size_t>> ans;
        for (size_t i = 0; i < parent.size(); i++) {
            ans[find_parent(i)].insert(i);
        }
        return ans;
    }
};

int main() {
    ll N, K, L;
    cin >> N >> K >> L;
    UnionFind tree0(N);
    rep(i,0,K) {
        ll p, q;
        cin >> p >> q;
        p--;
        q--;
        tree0.unite(p, q);
    }
    UnionFind tree1(N);
    rep(i,0,L) {
        ll r, s;
        cin >> r >> s;
        r--;
        s--;
        tree1.unite(r, s);
    }
    vector<uint64_t> to_group_idx(N);
    for (UnionFind* tree : {&tree0, &tree1}) {
        auto groups = tree->create_map_parent_to_elements();
        ll i = 0;
        for (auto& kv : groups) {
            for (ll elem : kv.second) {
                if (tree == &tree0) {
                    to_group_idx[elem] |= (i << 32);
                } else {
                    to_group_idx[elem] |= i;
                }
            }
            i++;
        }
    }
    unordered_map<uint64_t, vector<ll>> groups;
    rep(elem,0,N) {
        groups[to_group_idx[elem]].push_back(elem);
    }
    rep(elem,0,N) {
        cout << groups[to_group_idx[elem]].size();
        if (elem != N-1) {
            cout << " ";
        }
    }
    cout << endl;
}


Measured memory_bytes: 29780