// Slower C++ solution:
#include <bits/stdc++.h>



using namespace std;



const int inf = 0x3f3f3f3f;

const int maxv = 200010;

const int maxe = 100010;

int vertex, RailEdge, RoadEdge, cnt;

int RailHead[maxv], RoadHead[maxv], number[maxv], ans[maxv];

bool vis[maxv];

vector <int> v[maxv];

struct Edge

{

    int to, next;

}e[maxe * 4];



void addEdge(int *head, int from, int to)

{

    e[cnt].next = head[from];

    e[cnt].to = to;

    head[from] = cnt++;

}



void getNumberDFS(int cur)

{

    vis[cur] = true;

    number[cur] = cnt;

    for (int i = RoadHead[cur]; ~i; i = e[i].next)

    {

        int to = e[i].to;

        if (!vis[to])

            getNumberDFS(to);

    }

}



vector <int> valid;



void DFS(int cur)

{

    vis[cur] = true;

    int curNumber = number[cur];

    if (v[curNumber].size() == 0)

        valid.push_back(curNumber);

    v[curNumber].push_back(cur);

    for (int i = RailHead[cur]; ~i; i = e[i].next)

    {

        if (!vis[e[i].to])

            DFS(e[i].to);

    }

}



int main()

{

    memset(RailHead, -1, sizeof(RailHead));

    memset(RoadHead, -1, sizeof(RoadHead));

    for (int i = 0; i < maxv; i++)

        ans[i] = 1;





    int from, to;

    scanf("%d %d %d", &vertex, &RoadEdge, &RailEdge);

    for (int i = 0; i < RoadEdge; i++)

    {

        scanf("%d %d", &from, &to);

        addEdge(RoadHead, from, to);

        addEdge(RoadHead, to, from);

    }

    for (int i = 0; i < RailEdge; i++)

    {

        scanf("%d %d", &from, &to);

        addEdge(RailHead, from, to);

        addEdge(RailHead, to, from);

    }

    cnt = 0;

    for (int i = 1; i <= vertex; i++)

    {

        if (!vis[i])

        {

            getNumberDFS(i);

            cnt++;

        }

    }

//    printf("number:\n");

//    for (int i = 1; i <= vertex; i++)

//        printf("%d%c", number[i], i == vertex ? '\n' : ' ');

    memset(vis, false, sizeof(vis));

    for (int i = 1; i <= vertex; i++)

    {

        if (!vis[i])

        {

            DFS(i);

            for (int i = 0; i < valid.size(); i++)

            {

                int id = valid[i];

                for (int j = 0; j < v[id].size(); j++)

                    ans[v[id][j]] += v[id].size() - 1;

                v[id].clear();

            }

            valid.clear();

        }

    }

//    printf("answer:\n");

    for (int i = 1; i <= vertex; i++)

        printf("%d%c", ans[i], i == vertex ? '\n' : ' ');

    return 0;

}

/*

7 5 5

1 2

2 3

2 5

6 7

5 6

3 5

4 5

3 4

6 7

5 6

 

 1 1 4 1 4 4 4

 */






// Faster C++ solution for the same problem (measured speedup: 9.209152948180357x):
/*

7 4 4

1 2

2 3

2 5

6 7

3 5

4 5

3 4

6 7

*/

#include <bits/stdc++.h>

using namespace std; using ll = long long; using ld = long double; using pii = pair<int, int>; const int N = 5e5 + 5, M = 998244353, INF = 0x3f3f3f3f; const ll LNF = 0x3f3f3f3f3f3f3f3f; void Main();

void debug() { cerr << endl; } template <typename T, typename... Ts> void debug(T x, Ts... y) { cerr << "\033[31m" << x << "\033[0m"; if (sizeof...(y) > 0) cerr << ' '; debug(y...); } template <typename T> void debug(const T& a, int l, int r, char c) { for (int i = l; i <= r; ++i) cerr << "\033[31m" << a[i] << "\033[0m" << (i == r ? '\n' : c); }

void print() { cout << '\n'; } template <typename T, typename... Ts> void print(T x, Ts... y) { cout << x; if (sizeof...(y) > 0) cout << ' '; print(y...); } template <typename T> void print(const T& a, int l, int r, char c) { for (int i = l; i <= r; ++i) cout << a[i] << (i == r ? '\n' : c); }

void input() {} template <typename T, typename... Ts> void input(T& x, Ts&... y) { cin >> x; input(y...); } template <typename T> void input(T* a, int l, int r) { for (int i = l; i <= r; ++i) cin >> a[i]; } template <typename T> void input(vector<T>& a, int l, int r) { for (int i = l; i <= r; ++i) cin >> a[i]; }

template <typename T> void Max(T& a, T b) { if (a < b) a = b; } template <typename T> void Min(T& a, T b) { if (a > b) a = b; } template <typename T> void Add(T& a, T b) { a += b; if (a > M) a -= M; if (a < 0) a += M; } template <typename T> void Mul(T& a, T b) { a = a * b % M; } template <typename T> T Mod(T a) { return (a % M + M) % M; }

int main(int argc, char** argv) {

    ios::sync_with_stdio(0); cin.tie(0); /* cout << setprecision(10) << fixed; */

#ifdef Zmm

    if (argc) { freopen((string(*(argv)).substr(2, string(*(argv)).size() - 6) + string(".cpp")).c_str(), "r", stdin); string x; cin >> x; }

#endif

    Main();

}

struct DSU {

    int p[N];

    void init(int n) { iota(p + 1, p + n + 1, 1); }

    int find(int x) { return p[x] == x ? x : (p[x] = find(p[x])); }

    void unite(int u, int v) { p[find(u)] = find(v); }

} a, b;

void Main() {

    int n, K, L;

    input(n, K, L);

    a.init(n);

    b.init(n);

    for (int i = 0; i < K; ++i) {

        int u, v;

        input(u, v);

        a.unite(u, v);

    }

    for (int i = 0; i < L; ++i) {

        int u, v;

        input(u, v);

        b.unite(u, v);

    }

    map<pair<int, int>, int> mp;

    for (int i = 1; i <= n; ++i) ++mp[{a.find(i), b.find(i)}];

    for (int i = 1; i <= n; ++i) cout << mp[{a.p[i], b.p[i]}] << " \n"[i == n];

}