//#include "IntMod.h"
//typedef IntMod<1000000007> MInt;
 
#include <cstdio>
#include <iostream>
#include <string>
#include <vector>
#include <utility>
#include <algorithm>
#include <functional>
#include <cmath>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <iomanip>
 
using namespace std;
#define REP(i,a,n) for(int i = a; i < n; ++i)
#define REPM(i,n,a) for(int i = n - 1; i >= a; --i)
#define EPS 0.0001
#define INF 0x3FFFFFFF
#define INFD 1.0e+308
typedef long long LL;
typedef unsigned long long ULL;
 
typedef pair<LL, LL> PP;
 
 
class UnionFindTree {
	int whole_size_m;
	int* parent_p_m;	// 根である場合は自分自身の添え字を入れる
	int* rank_p_m;
	int* size_p_m;		// 集合のサイズ(根に大きさを書く)
 
	bool Is_valid_index(int index);
	int Root_of_rec(int index);
public:
	UnionFindTree(int whole_size);
	~UnionFindTree();
 
	int Root_of(int index);
	void Unite(int index_l, int index_r);
	bool Are_together(int index_l, int index_r);
	int Size_of_set(int index);
};
 
bool UnionFindTree::Is_valid_index(int index) {
	return index >= 0 && index < whole_size_m;
}
 
int UnionFindTree::Root_of_rec(int index) {
	if (parent_p_m[index] == index) {
		return index;
	} else {
		return parent_p_m[index] = Root_of_rec(parent_p_m[index]);
	}
}
 
UnionFindTree::UnionFindTree(int whole_size)
	: whole_size_m(whole_size) {
	parent_p_m = new int[whole_size_m];
	rank_p_m = new int[whole_size_m];
	size_p_m = new int[whole_size_m];
	for (int i = 0; i < whole_size_m; ++i) {
		parent_p_m[i] = i;
		rank_p_m[i] = 1;
		size_p_m[i] = 1;
	}
}
 
UnionFindTree::~UnionFindTree() {
	delete[] parent_p_m;
	delete[] rank_p_m;
	delete[] size_p_m;
}
 
int UnionFindTree::Root_of(int index) {
	if (Is_valid_index(index) == false) return -1;
	return Root_of_rec(index);
}
 
void UnionFindTree::Unite(int index_l, int index_r) {
	if (Is_valid_index(index_l) == false || Is_valid_index(index_r) == false) return;
	int root_l = Root_of(index_l);
	int root_r = Root_of(index_r);
	if (root_l == root_r) return;
 
	if (rank_p_m[root_l] > rank_p_m[root_r]) {
		parent_p_m[root_r] = root_l;
		size_p_m[root_r] += root_l;
	} else {
		parent_p_m[root_l] = root_r;
		size_p_m[root_l] += root_r;
		if (rank_p_m[root_l] == rank_p_m[root_r]) ++rank_p_m[root_r];
	}
}
 
bool UnionFindTree::Are_together(int index_l, int index_r) {
	return rank_p_m[index_l] == rank_p_m[index_r];
}
 
int UnionFindTree::Size_of_set(int index) {
	return size_p_m[index];
}

int N, K, L;
multimap<PP, int> M;
int connect[200001];

int main() {
	cin >> N >> K >> L;
	UnionFindTree Ur(N);
	UnionFindTree Ut(N);
	REP(i, 0, K) {
		int buf1, buf2;
		cin >> buf1 >> buf2;
		Ur.Unite(buf1 - 1, buf2 - 1);
	}
	REP(i, 0, L) {
		int buf1, buf2;
		cin >> buf1 >> buf2;
		Ut.Unite(buf1 - 1, buf2 - 1);
	}
	REP(i, 0, N) {
		M.insert(make_pair(PP(Ur.Root_of(i), Ut.Root_of(i)), i));
	}

	PP p_prev = { -1, -1 };
	vector<int> indices;
	for (auto it = M.begin(); it != M.end(); ++it) {
		if (it->first == p_prev) {
			indices.push_back(it->second);
		} else {
			for (int i = 0; i < indices.size(); ++i) {
				connect[indices[i]] = indices.size();
			}
			indices.clear();
			indices.push_back(it->second);
			p_prev = it->first;
		}
	}
	for (int i = 0; i < indices.size(); ++i) {
		connect[indices[i]] = indices.size();
	}
	REP(i, 0, N) {
		cout << connect[i] << (i == N - 1 ? '\n' : ' ');
	}
	return 0;
}

Measured memory_bytes: 18688