#include <iostream>
#include <string>
#include <algorithm>
#include <cassert>
#include <vector>
#include <map>
#include <unordered_map>

using namespace std;


struct UnionFind {
	vector<int> data;
	UnionFind(int size) : data(size, -1) { }
	bool unionSet(int x, int y) {
		x = root(x); y = root(y);
		if (x != y) {
			if (data[y] < data[x]) swap(x, y);
			data[x] += data[y]; data[y] = x;
		}
		return x != y;
	}
	bool findSet(int x, int y) {
		return root(x) == root(y);
	}
	int root(int x) {
		return data[x] < 0 ? x : data[x] = root(data[x]);
	}
	int size(int x) {
		return -data[root(x)];
	}
	//	using P = pair<int, int>;
	//	P wholeSizePair;
	//	UnionFind(P sizePair) : data(sizePair.first * sizePair.second, -1), wholeSizePair(sizePair) { }
	//	bool unionSet(P xPair, P yPair) {
	//		return unionSet(pairToInt(xPair), pairToInt(yPair));
	//	}
	//	bool findSet(P xPair, P yPair) {
	//		return root(xPair) == root(yPair);
	//	}
	//	P root(P xPair) {
	//		return intToPair(root(pairToInt(xPair)));
	//	}
	//	int size(P xPair) {
	//		return -data[root(pairToInt(xPair))];
	//	}
	//
	//	UnionFind(int sizePairFirst, int sizePairSecond) : UnionFind(make_pair(sizePairFirst, sizePairSecond)) { }
	//	bool unionSet(int xPairFirst, int xPairSecond, int yPairFirst, int yPairSecond) {
	//		return unionSet(pairToInt(make_pair(xPairFirst, xPairSecond)), pairToInt(make_pair(yPairFirst, yPairSecond)));
	//	}
	//	bool findSet(int xPairFirst, int xPairSecond, int yPairFirst, int yPairSecond) {
	//		return findSet(make_pair(xPairFirst, xPairSecond), make_pair(yPairFirst, yPairSecond));
	//	}
	//	P root(int xPairFirst, int xPairSecond) {
	//		return root(make_pair(xPairFirst, xPairSecond));
	//	}
	//	int size(int xPairFirst, int xPairSecond) {
	//		return size(make_pair(xPairFirst, xPairSecond));
	//	}
	//
	//private:
	//	int pairToInt(P p) {
	//		if (p.first < wholeSizePair.first && p.second < wholeSizePair.second) {
	//			return p.first*wholeSizePair.second + p.second;
	//		}
	//		else {
	//			cerr << "error:範囲外参照(UnionFind::pairToInt)" << endl;
	//			exit(1);
	//		}
	//	}
	//	P intToPair(int x) {
	//		if (x < wholeSizePair.first * wholeSizePair.second) {
	//			return make_pair(x / wholeSizePair.second, x % wholeSizePair.second);
	//		}
	//		else {
	//			cerr << "error:範囲外参照(UnionFind::intToPair)" << endl;
	//			exit(1);
	//		}
	//	}
};

struct pair_hash {
	template <class T1, class T2>
	std::size_t operator () (const std::pair<T1, T2> &p) const {
		auto h1 = std::hash<T1>{}(p.first);
		auto h2 = std::hash<T2>{}(p.second);

		// Mainly for demonstration purposes, i.e. works but is overly simple
		// In the real world, use sth. like boost.hash_combine
		return h1 ^ h2;
	}
};

int N, K, L;
int p, q;
int r, s;

void solve() {
	int ans;
	cin >> N >> K >> L;

	UnionFind uf_road(N + 1);
	for (int i = 0; i < K; i++)
	{
		cin >> p >> q;
		uf_road.unionSet(p, q);
	}
	UnionFind uf_metro(N + 1);
	for (int i = 0; i < L; i++)
	{
		cin >> r >> s;
		uf_metro.unionSet(r, s);
	}

	//unordered_map<pair<int, int>, int, pair_hash> um_both;
	map<pair<int, int>, int> mp_both;
	for (int i_city = 1; i_city <= N; i_city++)
	{
		mp_both[make_pair(uf_road.root(i_city), uf_metro.root(i_city))]++;
	}
	for (int i_city = 1; i_city <= N; i_city++)
	{
		ans = mp_both[make_pair(uf_road.root(i_city), uf_metro.root(i_city))];
		cout << ans << " ";
	}

	return;
}

int main() {
	solve();
	return 0;
}

Measured memory_bytes: 13568