#include <iostream>
#include <vector>
#include <algorithm>
#include <set>
using namespace std;

class UnionFind{
 public:
  int n;
  vector<int> parents;
  vector<int> ranks;
  vector<int> group_size;

  explicit UnionFind(int n){
    this->n = n;
    parents = vector<int>(n, -1);
    for(int i = 0; i < n; i++)
    {
      parents[i] = i;
    }
    ranks = vector<int>(n, 0);
    group_size = vector<int>(n, 1);
  }

  ///木の根を求める
  int findRoot(int target)
  {
    if(!isValidTarget(target))
    {
      cout << "targetの値が不正です" << endl;
      return -1;
    }
    if(parents[target] == target)
    {
      return target;
    }else{
      return parents[target] = findRoot(parents[target]);
    }
  }

  ///target1とtarget2の属する集合を併合
  void uniteGroup(int target1, int target2)
  {
    if(!isValidTarget(target1) || !isValidTarget(target2))
    {
      cout << "target1かtarget2の値が不正です" << endl;
      return;
    }
    int parent_target1 = findRoot(target1);
    int parent_target2 = findRoot(target2);
    if(parent_target1 == parent_target2)
    {
      ///すでに同じ集合に属している
      return;
    }
    if(ranks[parent_target1] < ranks[parent_target2])
    {
      parents[parent_target1] = parent_target2;
    }else{
      parents[parent_target2] = parent_target1;
      if(ranks[parent_target1] == ranks[parent_target2]) ranks[parent_target1]++;
    }
  }

  ///target1とtarget2が同じ集合に属するか
  bool same(int target1, int target2)
  {
    if(!isValidTarget(target1) || !isValidTarget(target2))
    {
      cout << "target1かtarget2の値が不正です" << endl;
      return false;
    }
    return findRoot(target1) == findRoot(target2);
  }

  //グループサイズの計算
  void calculateGroupSize()
  {
    //最初にiを親に持つノードの数を数える
    vector<int> groups(n, 0);
    for (int i = 0; i < n; ++i) {
      groups[parents[i]]++;
    }
    ///次に自身が属するグループの大きさを格納する
    for(int i = 0; i < n; i++)
    {
      group_size[i] = groups[parents[i]];
    }
  }

 private:
  bool isValidTarget(int target)
  {
    return !(target < 0 || target > parents.size() - 1);
  }
};


int main() {
  int n, k, l;
  cin >> n >> k >> l;
  vector<pair<int, int>> roads(k);
  vector<pair<int, int>> trains(l);
  for (int i = 0; i < k; ++i) {
    int p, q;
    cin >> p >> q;
    roads[i] = {p - 1, q - 1};
  }
  for (int i = 0; i < l; ++i) {
    int r, s;
    cin >> r >> s;
    trains[i] = {r - 1, s -1};
  }

  ///union find木を生成
  UnionFind allTree(n);
  UnionFind roadTree(n);
  UnionFind trainTree(n);
  for(auto road : roads)
  {
    if(!roadTree.same(road.first, road.second))
    {
      roadTree.uniteGroup(road.first, road.second);
    }
    if(!allTree.same(road.first, road.second))
    {
      allTree.uniteGroup(road.first, road.second);
    }
  }
  for(auto train : trains)
  {
    if(!trainTree.same(train.first, train.second)) {
      trainTree.uniteGroup(train.first, train.second);
    }
    if(!allTree.same(train.first, train.second))
    {
      allTree.uniteGroup(train.first, train.second);
    }
  }
  vector<pair<int, int>> vec(n);
  for(int i = 0; i < n; i++)
  {
    vec[i] = {roadTree.findRoot(i), trainTree.findRoot(i)};
  }
  sort(vec.begin(), vec.end());
  for(int i = 0; i < n; i++)
  {
    cout << upper_bound(vec.begin(), vec.end(), make_pair(roadTree.findRoot(i), trainTree.findRoot(i)))
        - lower_bound(vec.begin(), vec.end(), make_pair(roadTree.findRoot(i), trainTree.findRoot(i))) << " ";
  }
  cout << endl;
  return 0;
}


Measured memory_bytes: 10752