#include <iostream>
#include <algorithm>
#include <string>
#include <map>
#include <math.h>
#include <set>
#include <vector>

using namespace std;
typedef long long  ll;
#define rep(i,s,n)for(ll i=s;i<n;i++)
#define repe(i,s,n)for(ll i=s;i<=n;i++)

static const double PI = 3.1415926535897932384626433;

///////////////////////////
////Prime Creator//////////
///////////////////////////
//bool Prime[100001] = {};
//void createPrime() {
//	ll n = 100001;
//	rep(i, 0, n) Prime[i] = true;
//	Prime[0] = false;
//	Prime[1] = false;
//	rep(i, 2, n) {
//		if (Prime[i]) {
//			rep(j, 2, n) {
//				if (j*i >= n)break;
//				Prime[j*i] = false;
//			}
//		}
//	}
//}
///////////////////////////
///////////////////////////

/////////////////////////
//Warshal Floyid/////////
/////////////////////////
//initialize`
//static const ll LL_MAX = (ll)1 << 55;
//static const ll WF_MAX = 300;
//rep(i, 0, N)rep(j, 0, N) wf[i][j] = LL_MAX;
//ll wf[WF_MAX][WF_MAX];
//void WarshalFloyid(int size) {
//	rep(k, 0, size)rep(i, 0, size)rep(j, 0, size)wf[i][j] = min(wf[i][j], wf[i][k] + wf[k][j]);
//}
//
////Bellmon ford
//// 隣接リストで使う辺を表す型
//struct Edge {
//	ll to, cost;  // 辺の接続先頂点, 辺の重み
//	Edge(ll to, ll cost) : to(to), cost(cost) {}  // コンストラクタ
//};
//typedef vector<vector<Edge> > AdjList;  // 隣接リストの型
//AdjList graph;  // グラフの辺を格納した構造体
//				// graph[v][i]は頂点vから出るi番目の辺Edge
//static const ll INF = (ll)1 << 55;
//vector<ll> dist; // 最短距離
//
//// 戻り値がtrueなら負の閉路を含む
//bool bellman_ford(int n, int s) { // nは頂点数、sは開始頂点
//	dist = vector<ll>(n, INF);
//	dist[s] = 0; // 開始点の距離は0
//	for (int i = 0; i < n; i++) {
//		for (int v = 0; v < n; v++) {
//			for (int k = 0; k < graph[v].size(); k++) {
//				Edge e = graph[v][k];
//				if (dist[v] != INF && dist[e.to] > dist[v] + e.cost) {
//					dist[e.to] = dist[v] + e.cost;
//					if (i == n - 1) {
//						return true;
//					}
//				}
//			}
//		}
//	}
//	return false;
//}

//RMQ Segment Tree
//const int MAX_N = 1 << 17;
//int n, dat[2 * MAX_N - 1];
//
//void init(int n_) {
//	n = 1;
//	while (n < n_) n *= 2;
//	rep(i, 0, 2 * n - 1) dat[i] = INT_MAX;
//}
//
//void update(int k, int a) {
//	k += n - 1;
//	dat[k] = a;
//	while (k > 0) {
//		k = (k - 1) / 2;
//		dat[k] = min(dat[k * 2 + 1], dat[k * 2 + 2]);
//	}
//}
//
//int query(int a, int b, int k, int l, int r) {
//	if (r <= a || b <= l) return INT_MAX;
//
//	if (a <= l && r <= b)return dat[k];
//	else {
//		int vl = query(a, b, k * 2 + 1, l, (l + r) / 2);
//		int vr = query(a, b, k * 2 + 2, (l + r) / 2, r);
//		return min(vl, vr);
//	}
//}
//
//int main() {
//	init(8);
//
//	update(0, 5);
//	update(1, 3);
//	update(2, 7);
//	update(3, 9);
//	update(4, 6);
//	update(5, 4);
//	update(6, 1);
//	update(7, 2);
//
//	cout << query(0, 6, 0, 0, n - 1) << endl;
//	return 0;
//}

//BIT Binary Index Tree
//int bit[MAX_N + 1], n;
//int sum(int i) {
//	int s = 0;
//	while (i > 0) {
//		s += bit[i];
//		i -= i;
//	}
//	return s;
//}
//void add(int i, int x) {
//	while (i <= n) {
//		bit[i] += x;
//		i += i & -i;
//	}
//}

//union find
static const ll MAX_N = 200000;
ll par[MAX_N];
ll ran[MAX_N];
ll par2[MAX_N];
ll ran2[MAX_N];
ll a[MAX_N];
ll b[MAX_N];

void init(ll n) {
	rep(i, 0, n) {
		par[i] = i;
		ran[i] = 0;
		par2[i] = i;
		ran2[i] = 0;
	}
}

ll find(ll x) {
	if (par[x] == x)  return x;
	else return par[x] = find(par[x]);
}

void unite(ll x, ll y) {
	x = find(x);
	y = find(y);
	if (x == y) return;

	if (ran[x] < ran[y]) {
		par[x] = y;
	}
	else {
		par[y] = x;
		if (ran[x] == ran[y]) ran[x]++;
	}
}
bool same(ll x, ll y) {
	return find(x) == find(y);
}

ll find2(ll x) {
	if (par2[x] == x)  return x;
	else return par2[x] = find2(par2[x]);
}

void unite2(ll x, ll y) {
	x = find2(x);
	y = find2(y);
	if (x == y) return;

	if (ran2[x] < ran2[y]) {
		par2[x] = y;
	}
	else {
		par2[y] = x;
		if (ran2[x] == ran2[y]) ran2[x]++;
	}
}
bool same2(ll x, ll y) {
	return find2(x) == find2(y);
}

int main() {
	ll n; cin >> n;
	init(n);
	ll k, l; cin >> k >> l;
	rep(i, 0, k) {
		ll p, q; cin >> p >> q;
		unite(p - 1, q - 1);
	}
	rep(i, 0, l) {
		ll r, s; cin >> r >> s;
		unite2(r - 1, s - 1);
	}

	map<pair<ll, ll>, ll> ans;
	rep(i, 0, n) {
		a[i] = find(i);
		b[i] = find2(i);
	}

	rep(i, 0, n) ans[{a[i], b[i]}]++;
	rep(i, 0, n) cout << ans[{a[i], b[i]}] << endl;
	//rep(i, 0, n) ans[{par[i], par2[i]}]++;
	//rep(i, 0, n) cout << ans[{par[i], par2[i]}] << endl;

	return 0;
}

Measured memory_bytes: 21376