// Original C++ solution (slower):
#include <bits/stdc++.h>

using namespace std;



#define fr(i,n) _back

#define pb	push_back

#define eb	emplace_back

#define mk	make_pair

#define fi	first

#define se	second

#define endl	'\n'



typedef long long ll;

typedef pair<int,int> ii;

typedef vector<ii> vii;

const int INF = 0x3f3f3f3f;

const double PI = acos(-1.0);

const int T = 2e5 + 3;



int pai[3][T];

int peso[3][T];

vii g[T];

int n,k,l;



void init() {

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

        for(int j = 0; j <= n; j++) {

            pai[i][j] = j;

            peso[i][j] = 1;

        }

}



int find(int op, int x) {

    return (pai[op][x] == x? x : pai[op][x] = find(op,pai[op][x]));

}



void join(int op, int x, int y) {

    x = find(op,x);

    y = find(op,y);

    if(x == y) return;

    if(peso[op][x] < peso[op][y]) swap(x,y);

    pai[op][y] = x;

    peso[op][x] += peso[op][y];

}



int main() {

    ios_base::sync_with_stdio(false);

    cin >> n >> k >> l;

    init();



    while(k--) {

        int a,b; cin >> a >> b;

        if(find(0,a) != find(0,b)) join(0,a,b);

    }



    while(l--) {

        int a,b; cin >> a >> b;

        if(find(1,a) != find(1,b)) join(1,a,b);

    }



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

        g[find(0,i)].eb(find(1,i),i);



    for(int i = 1; i <= n; i++) {

        sort(g[i].begin(), g[i].end());

        for(int j = 1; j < g[i].size(); j++)

            if(g[i][j].fi == g[i][j-1].fi)

                join(2,g[i][j].se,g[i][j-1].se);

    }



    for(int i = 1; i <= n; i++) cout << peso[2][find(2,i)] << " ";

    cout << endl;



    return 0;

}


// Optimized solution to the same problem (faster):
//used C i/o for faster peformance



#include<bits/stdc++.h>

#define f first

#define s second

using namespace std;



int x,y,z,n,m,road[200005],rail[200005],connect[200005];

pair<pair<int,int>,int> total[200005];



int root (int ind) {

	if (road[ind] == ind) return ind; else 

	return road[ind] = root(road[ind]);

}



void onion(int l, int r) {

	if (root(l) != root(r)) road[root(l)] = root(r);

}



int root2(int ind) {

	if (rail[ind] == ind) return ind; else 

	return rail[ind] = root2(rail[ind]);

}



void onion2(int l, int r) {

	if (root2(l) != root2(r)) rail[root2(l)] = root2(r);

}



int main() {

	scanf("%d%d%d",&x,&y,&z);

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

		rail[i] = i;

		road[i] = i;

	}

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

		scanf("%d%d",&n,&m);

		onion(n,m);

	}

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

		scanf("%d%d",&n,&m);

		onion2(n,m);

	}

	for (int i = 1; i <= x; i++) {

		total[i] = make_pair(make_pair(root(i),root2(i)),i);

	}

	sort(total+1,total+1+x);

	total[x+1].f.f = total[x+1].f.s = -31415;

	stack<int> st; while (!st.empty()) st.pop();

	int a1 = 0,a2 = 0,b1 = 0,b2 = 0;

	for (int i = 1; i <= x+1; i++) {

		a1 = total[i].f.f, a2 = total[i].f.s;

		if (!(st.empty() || (a1 == b1 && a2 == b2))) {

			int tmp = st.size();

			while (!st.empty()) {

				connect[st.top()] += tmp-1;

				st.pop(); 

			}

		} 

		b1 = a1, b2 = a2;

		st.push(total[i].second);

	}

	for (int i = 1; i <= x; i++) {

		printf("%d ",connect[i]+1);

	}

}

// Fastest known solution for this problem: