#include <bits/stdc++.h>

using namespace std;

using ll = long long;
using dbl = double;
using pii = pair<int, int>;
using pl4 = pair<ll, ll>;
using vi = vector<int>;
using vvi = vector<vi>;
using vs = vector<string>;
using vvs = vector<vs>;
using vll = vector<ll>;
using vvll = vector<vll>;
using vvvll = vector<vvll>;
using vpii = vector<pii>;
using vvpii = vector<vpii>;
using vpl4 = vector<pl4>;
using vvpl4 = vector<vpl4>;
using vd = vector<dbl>;
using vvd = vector<vd>;

#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define pob pop_back()
#define pf push_front
#define pof pop_front()
#define sz size()
#define bgn begin()
#define en end()
#define asn assign
#define emp empty()
#define fr front()
#define bk back()
#define clr clear()
#define ins insert
#define ers erase
#define res resize
#define tp top()

#define p_q priority_queue

#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define rFOR(i,a,b) for(int i=(b);i>=(a);i--)
#define REP(i,a) FOR((i),0,(a)-1)
#define REP0(i,a) FOR((i),0,(a))
#define REP1(i,a) FOR((i),1,(a))
#define rREP(i,a) rFOR((i),0,(a)-1)
#define rREP0(i,a) rFOR((i),0,(a))
#define rREP1(i,a) rFOR((i),1,(a))
#define ROR(v,i) for(auto &(i):(v))
#define IOTA(a,n) iota((a).bgn,(a).en,(n))
#define SORT(a) sort((a).bgn,(a).en)
#define rSORT(a) sort((a).rbegin(),(a).rend())
#define UNIQUE(a) (a).erase(unique((a).bgn,(a).en),(a).en)
#define PREVP(a) prev_permutation((a).bgn,(a).en)
#define NEXTP(a) next_permutation((a).bgn,(a).en)
#define BINS(a,b) binary_search((a).bgn,(a).en,(b))
#define LOWB(a,b) (lower_bound((a).bgn,(a).en,(b))-(a).bgn)
#define UPB(a,b) (upper_bound((a).bgn,(a).en,(b))-(a).bgn)
#define CNT(a,b) count((a).bgn,(a).en,b)
#define SUM(a) accumulate((a).bgn,(a).en,0)
#define REV(a) reverse((a).bgn,(a).en)
#define REGS(a,b) regex_search((a),regex(b))
#define REGM(a,b) regex_match((a),regex(b))
#define yn(a) cout <<((a)?"yes":"no")<<endl;
#define Yn(a) cout <<((a)?"Yes":"No")<<endl;
#define YN(a) cout <<((a)?"YES":"NO")<<endl;
#define Imp(a) cout <<((a)?"Possible":"Impossible")<<endl;
#define IMP(a) cout <<((a)?"POSSIBLE":"IMPOSSIBLE")<<endl;
#define say(a) cout <<(a);
#define sal(a) cout <<(a)<<endl;
#define sak cout <<endl;
#define sas cout <<" ";
#define sat cout <<"\t";
#define dbg(a) cout <<(#a)<<": "<<(a)<<endl;
#define c2l(a) ((ll)(a-48))
#define a2l(a) ((ll)(a-97))
#define A2l(a) ((ll)(a-65))
#define l2c(a) ((char)(a+48))
#define l2a(a) ((char)(a+97))
#define l2A(a) ((char)(a+65))
#define DigN2(a) ((llabs(a)==0)?(1):((ll)(log2(double(llabs(a))))+1))
#define DigN10(a) ((llabs(a)==0)?(1):((ll)(log10(double(llabs(a))))+1))
#define Dig2(a,b) (((a)>>(b))&1)
#define Dig10(a,b) (ll)(((a)/((ll)(pow(10.0,(double)(b)))))%10)
#define Pow2(a) (1<<(a))
#define Pow10(a) ((ll)(pow(10.0,double(a))))
#define LSB(a) ((a)&(-(a)))
#define llin(a) ll (a);cin >>(a);
#define stin(a) string (a);cin >>(a);
#define vin(v) ROR((v),(i)){cin >>(i);};
#define vllin(v,N) vll (v)((N));vin(v);
#define vsin(v,N) vs (v)((N));vin(v);
#define rdn(a,b) ((a)/(b))
#define rou(a,b) ((((double(a)/double(b))-((a)/(b)))<0.5)?((a)/(b)):(((a)/(b))+1))
#define rup(a,b) ((((a)%(b))==0)?((a)/(b)):(((a)/(b))+1))
#define min(a,b) ((a<b)?(a):(b))
#define max(a,b) ((a>b)?(a):(b))
#define powll(a,b) (ll)(pow((double)(a),(double)(b)))
#define Triangle(x1,y1,x2,y2,x3,y3) (((x1)-(x2))*((y1)-(y3))-((x1)-(x3))*((y1)-(y2)))

#define int ll

const ll MOD = 1e9 + 7;
//const ll MOD = 998244353;
//const ll MOD = 9007199254740881;
const ll INF = 1LL << 60;
const double PI = acos(-1.0);
const string alp = "abcdefghijklmnopqrstuvwxyz";
const string ALP = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

ll Bset(ll a, ll b, ll c) {
	if (c) a |= b;
	else a &= ~b;
	return a;
}

class UFT {

public:
	ll size;
	ll mode;
	vll root;
	vll rank;
	UFT(ll sizeget, ll modeget = 0){
		size = sizeget;
		mode = modeget;
		root.res(size, 0);
		if (!mode) rank.res(size, 0);
		IOTA(root, 0);
	}
	ll find(ll x) {
		return root[x] == x ? x : root[x] = find(root[x]);
	}
	bool same(ll x, ll y) {
		return find(x) == find(y);
	}
	void unite(ll x, ll y) {
		x = find(x);
		y = find(y);
		if (x == y) return;
		if (mode) root[y] = x;
		else {
			if (rank[x] < rank[y]) {
				root[x] = y;
			}
			else {
				root[y] = x;
				if (rank[x] == rank[y]) rank[x]++;
			}
		}
	}
};

template <typename valtype> class SegT {

public:

	ll size;
	vector<valtype> v;

	valtype initv;
	function<valtype(valtype x, valtype y)> calc;

	SegT(ll sizeget, ll modeget = 0) {
		sizeset(sizeget);
		modeset(modeget);
		init();
	}
	SegT(vector<valtype> cpyvec, ll modeget = 0) {
		sizeset(cpyvec.sz);
		modeset(modeget);
		init();
		copy(cpyvec);
	}
	SegT(ll sizeget, valtype initvget, function<valtype(valtype x, valtype y)> calcget) {
		sizeset(sizeget);
		initv = initvget;
		calc = calcget;
		init();
	}
	SegT(vector<valtype> cpyvec, valtype initvget, function<valtype(valtype x, valtype y)> calcget) {
		sizeset(cpyvec.sz);
		initv = initvget;
		calc = calcget;
		init();
		copy(cpyvec);
	}
	void sizeset(ll rsize) {
		size = DigN2(rsize);
		if (rsize == Pow2(size - 1)) size--;
		return;
	}
	void modeset(ll mode) {
		switch (mode) {
		case 0:
			initv = 0;
			calc = [](valtype x, valtype y) {return x + y; };
			break;
		case 1:
			initv = INF;
			calc = [](valtype x, valtype y) {return min(x, y); };
			break;
		case 2:
			initv = -INF;
			calc = [](valtype x, valtype y) {return max(x, y); };
			break;
		}
		return;
	}
	void init() {
		v.asn(Pow2(size + 1) - 1, initv);
	}
	void copy(vector<valtype> cpyvec) {
		REP(i, min(cpyvec.sz, Pow2(size))) set(i, cpyvec[i]);
	}
	ll i2v(ll i) const{
		if (i < 0 || i >= Pow2(size)) return -1;
		return Pow2(size) + i - 1;
	}
	ll top(ll i) const{
		if (i == 0) return -1;
		return (i - 1) / 2;
	}
	pl4 bot(ll i) const{
		if (i + 1 >= Pow2(size)) return mp(-1, -1);
		return mp(2 * i + 1, 2 * i + 2);
	}
	void set(ll i, valtype x) {
		i = i2v(i);
		v[i] = x;
		while (i > 0) {
			i = top(i);
			v[i] = calc(v[bot(i).fi], v[bot(i).se]);
		}
		return;
	}
	void add(ll i, valtype x) {
		set(i, v[i2v(i)] + x);
		return;
	}
	valtype operator[](const ll &i) const {
		return v[i2v(i)];
	}
//	valtype que(ll a = 0, ll b = Pow2(size) - 1) {
	valtype que(ll a, ll b) {
		if (a == b) return v[i2v(a)];
		if (a > b) swap(a, b);
		valtype ans = initv;
		ll ai = i2v(a);
		ll bi = i2v(b);
		FOR(i, 1, size + 1) {
			if (a > b) break;
			if (a%Pow2(i)) {
				ans = calc(ans, v[ai]);
				a += Pow2(i - 1);
				ai = top(ai) + 1;
			}
			else {
				ai = top(ai);
			}
			if (a > b) break;
			if ((b + 1) % Pow2(i)) {
				ans = calc(ans, v[bi]);
				b -= Pow2(i - 1);
				bi = top(bi) - 1;
			}
			else {
				bi = top(bi);
			}
			if (a > b) break;
		}
		return ans;
	}


};

template <typename lentype> class Graph {

public:

	ll mode;

	ll size;
	vector<vector<lentype>> Edge;
	vector<vector<lentype>> Path;
	vector<vector<lentype>> Prev;
	vll VtxData;
	vvll EdgeData;
	vector<set<ll>> Adj;

	Graph(ll sizeGet = 0, ll modeget = 0) {
		size = sizeGet;
		mode = modeget;
		init();
	}
	void init() {
		VtxInit();
		PathInit();
		PrevInit();
		return;
	}
	void VtxInit() {
		VtxData.res(size + 1, 0);
		Edge.res(size + 1, vector<lentype>(size, 0));
		EdgeData.res(size + 1, vll(size, 0));
		Edge[size].asn(size, 0);
		EdgeData[size].asn(size, 0);
		Adj.res(size, set<ll>());
		REP(i, size) {
			Edge[i].res(size, 0);
			EdgeData[i].res(size, 0);
		}
		return;
	}
	void PathInit() {
		Path.res(size + 1, vector<lentype>(size, 0));
		Path[size].asn(size, 0);
		REP(i, size) {
			Path[i].res(size, 0);
		}
		return;
	}
	void PrevInit() {
		Prev.res(size + 1, vector<lentype>(size, 0));
		Prev[size].asn(size, 0);
		REP(i, size) {
			Prev[i].res(size, 0);
		}
		return;
	}
	bool chk(ll x) {
		return (x < 0 || x >= size);
	}
/*	ll addV(ll x) {
		size += x;
//		init();
		return size - x;
	}*/
	ll setEData(ll x, ll y, ll i, ll m = -1) {
		if (chk(x) || chk(y)) return -1;
		if (m != -1) {
			switch (mode) {
			case 0:
				EdgeData[x][y] = Bset(EdgeData[x][y], Pow2(i), m);
				EdgeData[y][x] = Bset(EdgeData[y][x], Pow2(i), m);
				break;
			case 1:
				EdgeData[x][y] = Bset(EdgeData[x][y], Pow2(i), m);
				break;
			}
		}
		return Dig2(EdgeData[x][y], i);
	}
	void setE(ll x, ll y, lentype c) {
		if (chk(x) || chk(y)) return;
		switch (mode) {
		case 0:
			Edge[x][y] = c;
			Edge[y][x] = c;
			conE(x, y, 1);
			conE(y, x, 1);
			Adj[x].ins(y);
			Adj[y].ins(x);
			break;
		case 1:
			Edge[x][y] = c;
			conE(x, y, 1);
			Adj[x].ins(y);
			break;
		}
	}
	ll slpV(ll x, ll m = -1) {
		if (chk(x)) return -1;
		if (m != -1) VtxData[x] = m;
		return VtxData[x];
	}
	ll conE(ll x, ll y, ll m = -1) {
		if (chk(x) || chk(y)) return -1;
		if (m == 0) {
			switch (mode) {
			case 0:
				Adj[x].ers(y);
				Adj[y].ers(x);
				break;
			case 1:
				Adj[x].ers(y);
				break;
			}
		}
		return setEData(x, y, 0, m);
	}
	ll slpE(ll x, ll y, ll m = -1) {
		return setEData(x, y, 1, m);
	}
	ll canP(ll x, ll y, ll m = -1) {
		if (x < 0 || x >= (size + 1)) return -1;
		if (chk(y)) return -1;
		if (m != -1) {
			EdgeData[x][y] = Bset(EdgeData[x][y], Pow2(2), m);
		}
		return Dig2(EdgeData[x][y], 2);
	}
/*	ll tryP(ll x, ll y, ll m = -1) {
		return setEData(x, y, 3, m);
	}*/
	bool canE(ll x, ll y) {
		if (chk(x) || chk(y)) return false;
		if (slpV(x) || slpV(y) || slpE(x, y) || !conE(x, y)) return false;
		return true;
	}
	lentype getE(ll x, ll y) {
		return canE(x, y) ? Edge[x][y] : INF;
	}
/*	void Dijk(ll x) {
		p_q<pair<lentype, ll>, vector<pair<lentype, ll>>, greater<pair<lentype, ll>>> Q;
		pair<lentype, ll> now;
		REP(i, size) {
			canP(x, i, 0);
			tryP(x, i, x == i);
		}
		Path[x][x] = 0;
		Prev[x][x] = x;
		Q.push(mp(0, x));
		while (!Q.emp) {
			now = Q.top();
			Q.pop();
			if (canP(x, now.se)) continue;
			//			if (Path[x][now.se] < now.fi) continue;
			canP(x, now.se, 1);
			tryP(x, now.se, 0);
			REP(i, size) {
				if (canP(x, i)) continue;
				if (canE(now.se, i)) {
					if (tryP(x, i)) {
						if (Path[x][i] > Path[x][now.se] + Edge[now.se][i]) {
							Path[x][i] = Path[x][now.se] + Edge[now.se][i];
							Prev[x][i] = now.se;
							Q.push(mp(Path[x][i], i));
						}
					}
					else {
						Path[x][i] = Path[x][now.se] + Edge[now.se][i];
						Prev[x][i] = now.se;
						Q.push(mp(Path[x][i], i));
						tryP(x, i, 1);
					}
				}
			}
		}
	}*/
	void Dijk(ll x) {
		pair<lentype, ll> now;
		SegT<pair<lentype, ll>> Q(size, mp(-1, -1), [](pair<lentype, ll> l, pair<lentype, ll> r) {
			if (l.se == -1) return r;
			if (r.se == -1) return l;
			return l.fi < r.fi ? l : r;
		});
		REP(i, size) {
			canP(x, i, 0);
		}
		Q.set(x, mp(0, x));
		Path[x][x] = 0;
		Prev[x][x] = x;
		while (Q.que(0, size - 1).se != -1) {
			now = Q.que(0, size - 1);
			Q.set(now.se, mp(-1, -1));
			canP(x, now.se, 1);
			ROR(Adj[now.se], i) {
				if (canP(x, i)) continue;
				if (canE(now.se, i)) {
					if (Q[i].se == -1) {
						Path[x][i] = Path[x][now.se] + Edge[now.se][i];
						Prev[x][i] = now.se;
						Q.set(i, mp(Path[x][i], i));
					}
					else {
						if (Path[x][i] > Path[x][now.se] + Edge[now.se][i]) {
							Path[x][i] = Path[x][now.se] + Edge[now.se][i];
							Prev[x][i] = now.se;
							Q.set(i, mp(Path[x][i], i));
						}
					}
				}
			}
		}
	}
	lentype Prim(ll x = 0) {
		lentype ans = 0;
		pair<lentype, ll> now;
		SegT<pair<lentype, ll>> Q(size, mp(-1, -1), [](pair<lentype, ll> l, pair<lentype, ll> r) {
			if (l.se == -1) return r;
			if (r.se == -1) return l;
			return l.fi < r.fi ? l : r;
		});
		REP(i, size) {
			canP(size, i, 0);
		}
		Q.set(x, mp(0, x));
		Path[size][x] = 0;
		Prev[size][x] = x;
		while (Q.que(0, size - 1).se != -1) {
			now = Q.que(0, size - 1);
			Q.set(now.se, mp(-1, -1));
			canP(size, now.se, 1);
			ans += Path[size][now.se];
			ROR(Adj[now.se], i) {
				if (canP(size, i)) continue;
				if (canE(now.se, i)) {
					if (Q[i].se == -1) {
						Path[size][i] = Edge[now.se][i];
						Prev[size][i] = now.se;
						Q.set(i, mp(Path[size][i], i));
					}
					else {
						if (Path[size][i] > Edge[now.se][i]) {
							Path[size][i] = Edge[now.se][i];
							Prev[size][i] = now.se;
							Q.set(i, mp(Path[size][i], i));
						}
					}
				}
			}
		}
		return ans;
	}

	//EdgeData 1(slp)0(con)
	//init notsleep disconnected(00)

};

ll gcd(ll a, ll b) { if (b == 0)return a; return gcd(b, a%b); }
ll lcm(ll a, ll b) { return a / gcd(a, b)*b; }

pl4 Bezout(ll a, ll b) {
	if (b != 0) {
		pl4 xy;
		xy = Bezout(b, a%b);
		return mp(xy.se, xy.fi - ((a / b)*xy.se));
	}
	if (b == 0) {
		return mp(1, 0);
	}
}
pl4 Bez(ll a, ll b, ll c) {
	pl4 xy;
	ll x, y, z, gc;
	xy = Bezout(a, b);
	gc = gcd(a, b);
	if (c%gc != 0) return mp(-1, -1);
	x = xy.fi*(c / gc); y = xy.se*(c / gc);
	if (x < 0) z = rup(-x, (b / gc));
	if (x >= 0) z = -x / (b / gc);
	x += z * (b / gc);
	y -= z * (a / gc);
	return mp(x, y);
}

void salv(vll v) {
	say("{");
	FOR(i, 0, v.sz - 1) {
		say(v[i]);
		if (i != v.sz - 1) say(",");
	}
	sal("}")
}

ll DigS10(ll n) {
	ll m = 0;
	FOR(i, 0, DigN10(n) - 1) {
		m += (ll)((llabs(n) % (ll)(pow(10.0, (double)(i + 1)))) / (ll)(pow(10.0, (double)i)));
	}
	return m;
}

ll isP(ll n) {
	if (n <= 1) return 0;
	FOR(i, 2, (ll)sqrt(n)) {
		if (n%i == 0) return 0;
	}
	return 1;
}

vll FactM(1, 1);
vll FactMI(1, 1);

ll PowM(ll a, ll b) {
	ll ans = 1, x = (a%MOD);
	FOR(i, 0, DigN2(b) - 1) {
		if (Dig2(b, i) == 1) ans = (ans*x) % MOD;
		if (i != (DigN2(b) - 1)) x = (x*x) % MOD;
	}
	return ans;
}

ll Mod(ll a) {
	a %= MOD;
	a = (a + MOD) % MOD;
	return a;
}

ll InvM(ll a) {
	a = Mod(a);
	a = PowM(a, MOD - 2);
	return a;
}

void CFactM(ll n) {
	if (FactM.sz <= n) {
		FOR(i, FactM.sz, n) {
			FactM.pb((FactM[i - 1] * (i%MOD)) % MOD);
		}
	}
	return;
}

void CFactMI(ll n) {
	CFactM(n);
	if (FactMI.sz < (n + 1)) FactMI.res(n + 1, -1);
	if (FactMI[n] == -1) FactMI[n] = PowM(FactM[n], MOD - 2);
	rFOR(i, 1, n - 1) {
		if (FactMI[i] != -1) break;
		FactMI[i] = ((FactMI[i + 1] * ((i + 1) % MOD)) % MOD);
	}
	return;
}

ll CombM(ll n, ll k) {
	if ((n < 0) || (k < 0)) return 0;
	if (n < k) return 0;
	if (n + 1 > FactMI.sz) CFactMI(n);
	return ((((FactMI[k] * FactMI[n - k]) % MOD)*FactM[n]) % MOD);
}

ll LIS(vll v, ll m = 0) {

	if (v.sz > 0) {
		ll ans = 0;
		vll dp(v.sz, INF);
		FOR(i, 0, v.sz - 1) {
			dp[m ? UPB(dp, v[i]) : LOWB(dp, v[i])] = v[i];
		}
		FOR(i, 0, v.sz - 1) {
			if (dp[i] == INF) break;
			ans++;
		}
		return ans;
	}
	else {
		return 0;
	}

}

void cmprs(vll& v) {
	if (v.sz == 0) return;
	vll vv(v);
	IOTA(vv, 0);
	sort(vv.bgn, vv.en, [&](ll v1, ll v2) {return v[v1] < v[v2]; });
	IOTA(v, 0);
	sort(v.bgn, v.en, [&](ll v1, ll v2) {return vv[v1] < vv[v2]; });
	return;
}

ll BblCnt(vll v) {
	cmprs(v);
	SegT<ll> b(v.sz, 0);
	ll ans = 0;
	REP(i, v.sz) {
		ans += (i - b.que(0, v[i]));
		b.add(v[i], 1);
	}
	return ans;
}

ll Bsrch(function<bool(ll x)> f, ll mi, ll ma) {
	ll ng = mi - 1, ok = ma, mid;
	while (ok - ng > 1) {
		mid = (ng + ok) / 2;
		(f(mid) ? ok : ng) = mid;
	}
	return ok;
}

/*
std::cout << std::fixed;
std::cout << std::setprecision(2) << 3.141; // "3.14"
std::cout << std::setprecision(2) << 3.0;   // "3.00"
*/

signed main() {

	ll N, K, L;
	cin >> N >> K >> L;
	UFT d(N);
	UFT t(N);
	ll a, b;
	REP(i, K) {
		cin >> a >> b;
		d.unite(a - 1, b - 1);
	}
	REP(i, L) {
		cin >> a >> b;
		t.unite(a - 1, b - 1);
	}
	map<pair<ll, ll>, ll> ma;
	REP(i, N) {
		ma[mp(d.find(i), t.find(i))]++;
	}
	say(ma[mp(d.find(0), t.find(0))]);
	REP1(i, N - 1) {
		say(" ");
		say(ma[mp(d.find(i), t.find(i))]);
	}

}

Measured memory_bytes: 18048