// #include "ggraph.hh"

#include <cstdlib>
#include <vector>
#include <list>
#include <map>
#include <iostream>
#include <cassert>
#include <memory>
// #include "tree.hh"

#include <list>
#include <vector>
#include <iostream>
using namespace std;

// template<typename T> 
// class TreeNode{
// public:
// 	TreeNode<T>(TreeNode<T>* parent,T data):parent(parent),data(data){};
// 	TreeNode<T>* parent;
// 	list<TreeNode<T>> children;
// 	T data;
// 	void add_child(T data){
// 		children.push_back(TreeNode<T>(this,data));
// 	}
// };

class VectorTree{
public:
	VectorTree(size_t n):children(n),parent(n,-1){};
	vector<vector<int>> children;
	vector<int> parent;
	void add(int p,int c){
// 		cout << "parent:" << p << " child:" << c <<endl;
		parent[c] = p;
		children[p].push_back(c);
	}
	size_t size(){
		return parent.size();
	}
	int root(int x){
		if(parent[x] == -1)
			return x;
		else
			return root(parent[x]);
	}
};


using namespace std;

using Weight = long long;
class Edge{
public:
	int src,dest;
	Edge(int src, int dest): src(src),dest(dest){};
	virtual Weight get_weight()const {return 1;};
	virtual bool operator<(const Edge& other) const {
		return get_weight() < other.get_weight();
	}
};

class WeightedEdge : public Edge{
public:
	Weight weight;
	WeightedEdge(size_t src, size_t dest,Weight weight): Edge(src,dest),weight(weight){};
	virtual Weight get_weight()const {return weight;};
};

class Graph{
private:
	size_t n;
public:
	Graph(size_t n):n(n),adj_lst(n),rev_adj_lst(n){};
	vector<std::unique_ptr<Edge>> edges;
	vector<vector<Edge*>> adj_lst;
	vector<vector<Edge*>> rev_adj_lst;
	vector<Edge*>& get_outgoing(int index);
	vector<Edge*>& get_incoming(int index);

	virtual void add_edge(unique_ptr<Edge>&& e);
	size_t size()const {return n;};

};

void Graph::add_edge(std::unique_ptr<Edge>&& e){
	adj_lst[e->src].push_back(e.get());
	rev_adj_lst[e->dest].push_back(e.get());
	edges.push_back(move(e));
}

vector<Edge*>& Graph::get_outgoing(int index){
	return adj_lst[index];
}
vector<Edge*>& Graph::get_incoming(int index){
	return rev_adj_lst[index];
}

// #include "kosaraju.hh"

// #include "ggraph.hh"

#include <deque>

namespace kosaraju{
	vector<int> cmp;
	vector<bool> visited;
	int cmp_num;
	deque<size_t> l;

	void visit(size_t v, Graph& g){
		if(visited[v])
			return;
		visited[v] = true;
		for(auto e: g.adj_lst[v]){
			visit(e->dest,g);
		}
		l.push_front(v);
	}

	void assign(size_t v,int num, Graph& g){
		if(cmp[v] >= 0)
			return;
		cmp[v] = num;
		for(auto e: g.rev_adj_lst[v]){
			assign(e->src,num,g);
		}
	}

	vector<int> kosaraju(Graph& g){
		cmp.assign(g.size(),-1);
		visited.assign(g.size(),false);
		int cmp_num = 0;

		for(size_t i = 0; i < g.size();i++){
			visit(i,g);
		}
		for(size_t i = 0; i < g.size();i++){
			if(cmp[l[i]] < 0){
				assign(l[i],cmp_num,g);
				cmp_num++;
			}
		}
		return cmp;
	}
}

#include <memory>
#include <map>
using namespace std;
using P = pair<int,int>;
map<P,int> m;

int main(){
	int n,k,l;
	cin >> n >> k >> l;

	Graph g1(n);
	Graph g2(n);
	for(int i = 0;i < k; i++){
		int p,q;
		cin >> p >> q;
		g1.add_edge(unique_ptr<Edge>(new Edge(p-1,q-1)));
		g1.add_edge(unique_ptr<Edge>(new Edge(q-1,p-1)));
	}

	for(int i = 0;i < l; i++){
		int r,s;
		cin >> r >> s;
		g2.add_edge(unique_ptr<Edge>(new Edge(r-1,s-1)));
		g2.add_edge(unique_ptr<Edge>(new Edge(s-1,r-1)));
	}

	auto res1 = kosaraju::kosaraju(g1);
	auto res2 = kosaraju::kosaraju(g2);

	for(int i = 0;i < n;i++){
		m[P(res1[i],res2[i])]+=1;
	}
	for(int i = 0;i < n;i++){
		cout << m[P(res1[i],res2[i])]<< " ";
	}
	cout << endl;
}



Measured memory_bytes: 63988