use std::io::prelude::BufRead;
use std::io::StdinLock;

pub fn read_line(locked_stdin: &mut StdinLock) -> std::io::Result<String> {
    let mut buf = String::new();
    locked_stdin.read_line(&mut buf).map(|_| buf)
}

pub fn read_to_vec<T: std::str::FromStr>(locked_stdin: &mut StdinLock) -> Vec<T> {
    read_line(locked_stdin).unwrap()
        .split_whitespace()
        .map(|e| e.parse().ok().unwrap())
        .collect()
}

pub struct ConnectedUGraph {
    id: usize,
    nodes: Vec<usize>,
}

pub struct UGraph {
    adj_lists: Vec<Vec<usize>>,
    n: usize,
    conn: Vec<ConnectedUGraph>,
    conn_index: Vec<Option<usize>>,
}

impl ConnectedUGraph {
    pub fn nodes(&self) -> &Vec<usize> {
        &self.nodes
    }

    pub fn id(&self) -> usize {
        self.id
    }
}

impl UGraph {
    pub fn new(n: usize) -> UGraph {
        let mut adj_lists = Vec::new();
        let mut conn_index = Vec::new();
        adj_lists.resize(n, Vec::new());
        conn_index.resize(n, None);
        UGraph{
            adj_lists: adj_lists,
            n: n,
            conn: Vec::new(),
            conn_index: conn_index,
        }
    }

    pub fn push_edge(&mut self, edge: [usize; 2]) {
        // O(1)
        self.adj_lists.get_mut(edge[0]).map(|v| v.push(edge[1]));
        self.adj_lists.get_mut(edge[1]).map(|v| v.push(edge[0]));
    }

    pub fn neighbors_of(&self, node: usize) -> Option<&Vec<usize>> {
        // O(1)
        self.adj_lists.get(node)
    }

    fn dfs_connected(&self, start: usize) -> Vec<usize> {
        let mut todo = Vec::new();
        let mut found = std::collections::HashSet::new();
        let mut nodes = Vec::new();

        found.insert(start);
        nodes.push(start);
        todo.push(start);
        while let Some(visit) = todo.pop() {
            for &neighbor in self.neighbors_of(visit).unwrap().iter() {
                if ! found.contains(&neighbor) {
                    found.insert(neighbor);
                    nodes.push(neighbor);
                    todo.push(neighbor);
                }
            }
        }

        nodes
    }

    pub fn connected_with(&mut self, start: usize) -> Option<&ConnectedUGraph> {
        if let Some(&s) = self.conn_index.get(start) {
            if let Some(i) = s { return self.conn.get(i); }
        } else { return None; }

        let nodes = self.dfs_connected(start);
        let id = self.conn.len();
        for &i in nodes.iter() {
            self.conn_index[i] = Some(id);
        }
        self.conn.push(ConnectedUGraph{ id: id, nodes: nodes });
        self.conn.last()
    }
}

fn main() {
    let (n, k, l);
    let mut road_graph;
    let mut rail_graph;

    {
        let stdin = std::io::stdin();
        let mut lkin = stdin.lock();
        let mut input = read_to_vec(&mut lkin).into_iter();
        n = input.next().unwrap();
        k = input.next().unwrap();
        l = input.next().unwrap();
        road_graph = UGraph::new(n);
        rail_graph = UGraph::new(n);

        for _ in 0..k {
            input = read_to_vec(&mut lkin).into_iter();
            road_graph.push_edge([input.next().unwrap() - 1, input.next().unwrap() - 1]);
        }

        for _ in 0..l {
            input = read_to_vec(&mut lkin).into_iter();
            rail_graph.push_edge([input.next().unwrap() - 1, input.next().unwrap() - 1]);
        }
    }

    let mut ans = std::collections::HashMap::new();

    for i in 0..n {
        let tuple = (road_graph.connected_with(i).unwrap().id(), rail_graph.connected_with(i).unwrap().id());
        *ans.entry(tuple).or_insert(0) += 1;
    }

    for i in 0..n {
        let tuple = (road_graph.connected_with(i).unwrap().id(), rail_graph.connected_with(i).unwrap().id());
        print!("{} ", ans.get(&tuple).unwrap_or(&1));
    }

    println!("");
}


Measured memory_bytes: 62508