Problem:
Problem F: Name the Crossing

The city of Kyoto is well-known for its Chinese plan: streets are
either North-South or East-West. Some streets are numbered, but most
of them have real names.

Crossings are named after the two streets crossing there,
e.g. Kawaramachi-Sanjo is the crossing of Kawaramachi street and Sanjo
street. But there is a problem: which name should come first?
At first the order seems quite arbitrary: one says Kawaramachi-Sanjo
(North-South first) but Shijo-Kawaramachi (East-West first). With some
experience, one realizes that actually there
seems to be an "order" on the streets, for instance in the above
Shijo is "stronger" than Kawaramachi, which in turn is "stronger" than
Sanjo.
One can use this order to deduce the names of other crossings.

You are given as input a list of known crossing names X-Y.
Streets are either North-South or East-West, and only orthogonal streets
may cross.

As your list is very incomplete, you start by completing it using
the following rule:

two streets A and B have equal strength if (1) to (3) are
all true:

they both cross the same third street C in the input

there is no street D such that D-A and B-D appear in the input

there is no street E such that A-E and E-B appear in the input

We use this definition to extend our strength relation:

A is stronger than B, when there is a
sequence A = A1, A2, ..., An = B,
with n at least 2,

where, for any i in 1 .. n-1, either
Ai-Ai+1 is an input crossing or
Ai and Ai+1 have equal strength.

Then you are asked whether some other possible crossing names X-Y are
valid. You should answer affirmatively if you can infer the validity of a
name, negatively if you cannot. Concretely:

YES if you can infer that the two streets are orthogonal, and X
is stronger than Y

NO otherwise

Input

The input is a sequence of data sets, each of the form

N
Crossing1
...
CrossingN
M
Question1
...
QuestionM

Both Crossings and Questions are of the form

X-Y

where X and Y are strings of alphanumerical characters,
of lengths no more than 16. There is no white space, and case matters
for alphabetical characters.

N and M are between 1 and 1000 inclusive, and there are
no more than 200 streets in a data set.

The last data set is followed by a line containing a zero.

Output

The output for each data set should be composed of M+1 lines,
the first one containing the number of streets
in the Crossing part of the input, followed by the answers to
each question, either YES or NO without any spaces.

Sample Input

7
Shijo-Kawaramachi
Karasuma-Imadegawa
Kawaramachi-Imadegawa
Nishioji-Shijo
Karasuma-Gojo
Torimaru-Rokujo
Rokujo-Karasuma
6
Shijo-Karasuma
Imadegawa-Nishioji
Nishioji-Gojo
Shijo-Torimaru
Torimaru-Gojo
Shijo-Kawabata
4
1jo-Midosuji
Midosuji-2jo
2jo-Omotesando
Omotesando-1jo
4
Midosuji-1jo
1jo-Midosuji
Midosuji-Omotesando
1jo-1jo
0

Output for the Sample Input

8
YES
NO
YES
NO
YES
NO
4
YES
YES
NO
NO

Solution in Rust (judge verdict: Accepted)

use std::collections::hash_set::Iter;
use std::rc::Rc;
use std::ops::DivAssign;
use std::ops::MulAssign;
use std::ops::SubAssign;
use std::collections::BinaryHeap;
use std::str::FromStr;
use std::collections::HashSet;
use std::collections::BTreeMap;
use std::fmt::Display;
use std::ops::Neg;
use std::ops::Div;
use std::ops::Mul;
use std::ops::Add;
use std::ops::{AddAssign, Sub};
use std::cmp::max;
use std::collections::VecDeque;
use std::cmp::min;
use std::collections::{HashMap, BTreeSet};
use std::cmp::Ordering;
use std::fmt::Debug;

fn read_line() -> String {
    let mut buffer = String::new();
    std::io::stdin().read_line(&mut buffer).expect("No Line");
    buffer.trim().to_owned()
}
fn read_lines<T: std::str::FromStr>(count: usize) -> Vec<T> {
    let mut buffer = String::new();
    let mut vec = Vec::with_capacity(count);
    for _ in 0 .. count {
        std::io::stdin().read_line(&mut buffer).expect("No Line");
        vec.push(buffer.trim().parse().ok().expect("Can't Parse"));
        buffer.clear();
    }
    vec
}
fn read_tabulate<R, T: Fn(&str)->R> (count: usize, transformer: T) -> Vec<R> {
    let mut buffer = String::new();
    let mut vec = Vec::with_capacity(count);
    for _ in 0 .. count {
        std::io::stdin().read_line(&mut buffer).expect("No Line");
        vec.push(transformer(buffer.trim()));
        buffer.clear();
    }
    vec
}
fn read_value<T: std::str::FromStr>() -> T {
    read_line().trim().parse().ok().unwrap()
}
fn read_values<T: std::str::FromStr>() -> Vec<T> {
    read_line().trim().split_whitespace().map(|x| x.parse().ok().expect("Can't Parse")).collect::<Vec<T>>()
}
macro_rules! freeze {
    ($($id:ident), *) => {
        $(let $id = $id;)*
    };
}
macro_rules! read_map {
    ($ident: ident: [$block: block; $size: expr]) => {
        let $ident = (0 .. $size).into_iter().map(|_| $block).collect::<Vec<_>>();
    };
    (mut $ident: ident: [$block: block; $size: expr]) => {
        let mut $ident = (0 .. $size).into_iter().map(|_| $block).collect::<Vec<_>>();
    };
}
macro_rules! read {
    (mut $ident: ident: String) => {
        let mut $ident = read_value::<String>();
    };
    ($ident: ident: String) => {
        let $ident = read_value::<String>();
    };
    (mut $ident: ident: [$ty:ty]) => {
        let mut $ident = read_values::<$ty>();
    };
    ($ident: ident: [$ty:ty]) => {
        let $ident = read_values::<$ty>();
    };
    (mut $ident: ident: [[$ty:ty]; $size: expr]) => {
        let mut $ident = (0 .. $size).into_iter().map(|_| read_values::<$ty>()).collect::<Vec<_>>();
    };
    ($ident: ident: [[$ty:ty]; $size: expr]) => {
        let $ident = (0 .. $size).into_iter().map(|_| read_values::<$ty>()).collect::<Vec<_>>();
    };
    (mut $ident: ident: [$ty:ty; $size:expr]) => {
        let mut $ident = read_lines::<$ty>($size);
    };
    ($ident: ident: [$ty:ty; $size:expr]) => {
        let $ident = read_lines::<$ty>($size);
    };
    ($ident: ident: [$block: block; $size: expr]) => {
        let $ident = (0 .. $size).into_iter().map(|_| $block).collect::<Vec<_>>();
    };
    (mut $ident: ident: [$block: block; $size: expr]) => {
        let mut $ident = (0 .. $size).into_iter().map(|_| $block).collect::<Vec<_>>();
    };
    ($($token: tt)*) => {
        let mut iter = read_values::<String>().into_iter();
        read_from_iter!(iter; $($token)*);
    };
}
macro_rules! read_from_iter {
    ($iter:expr; mut $ident:ident:$ty:ty, $($rest:tt)*) => {
        let mut $ident = $iter.next().unwrap().parse::<$ty>().expect("Can't Parse");
        read_from_iter!($iter; $($rest)*);
    };
    ($iter:expr; $ident:ident:$ty:ty, $($rest:tt)*) => {
        let $ident = $iter.next().unwrap().parse::<$ty>().expect("Can't Parse");
        read_from_iter!($iter; $($rest)*);
    };
    ($iter:expr; mut $ident:ident:$ty:ty) => {
        let mut $ident = $iter.next().unwrap().parse::<$ty>().expect("Can't Parse");
    };
    ($iter:expr; $ident:ident:$ty:ty) => {
        let $ident = $iter.next().unwrap().parse::<$ty>().expect("Can't Parse");
    };
    ($iter: expr; ) => {};
}
struct KeyValue<K, V> {
    key: K,
    value: V
}
impl <K: PartialOrd, V> PartialEq for KeyValue<K, V> {
    fn eq(&self, other: &Self) -> bool {
        self.key.eq(&other.key)
    }
}
impl <K: PartialOrd, V> Eq for KeyValue<K, V> {}
impl <K: PartialOrd, V> PartialOrd for KeyValue<K, V> {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        self.key.partial_cmp(&other.key)
    }
}
impl <K: PartialOrd, V> Ord for KeyValue<K, V> {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.key.partial_cmp(&other.key).ok_or("Can't Compare").unwrap()
    }
}

struct UnionFind {
    vec: Vec<i32>
}
impl UnionFind {
    fn new(size: usize) -> UnionFind {
        UnionFind{vec: vec![-1; size]}
    }
    fn find(&mut self, a: usize) -> usize {
        if self.vec[a] < 0 {
            a
        }else {
            let parent = self.vec[a];
            let root = self.find(parent as usize);
            self.vec[a] = root as i32;
            root
        }
    }
    fn same(&mut self, a: usize, b: usize) -> bool {
        self.find(a) == self.find(b)
    }
    fn unite(&mut self, mut a: usize, mut b: usize) {
        a = self.find(a);
        b = self.find(b);
        if a == b {return ;}
        if self.vec[a] < self.vec[b] {
            self.vec[a] += self.vec[b];
            self.vec[b] = a as i32;
        }else {
            self.vec[b] += self.vec[a];
            self.vec[a] = b as i32;
        }
    }
}
fn main() {
    loop {
        read!(n: usize);
        if n == 0 {break;}
        read_map!(cross: [{
            read!(name: String);
            let names = name.split('-').collect::<Vec<_>>();
            let prior = names[0];
            let sub = names[1];
            (prior.to_owned(), sub.to_owned())
        }; n]);
        let mut roads = HashMap::<String, Vec<HashSet<String>>>::new();
        for t in &cross {
            let p = t.0.to_owned();
            let s = t.1.to_owned();
            roads.entry(p.to_owned()).or_insert(vec![HashSet::new(); 2])[1].insert(s.to_owned());
            roads.entry(s.to_owned()).or_insert(vec![HashSet::new(); 2])[0].insert(p.to_owned());
            //println!("{:?}", roads);
        }
        let names = roads.iter().map(|(s, _)| s).cloned().collect::<Vec<_>>();
        let mut indices = HashMap::<String, usize>::new();
        for i in 0 .. names.len() {
            indices.insert(names[i].to_owned(), i);
        }
        let mut same_level = UnionFind::new(roads.len());
        for i in 0 .. names.len() {
            for j in 0 .. i {
                if roads[&names[i]][0].intersection(&roads[&names[j]][1]).next().is_none() && 
                    roads[&names[j]][0].intersection(&roads[&names[i]][1]).next().is_none() && 
                    !(roads[&names[i]][0].intersection(&roads[&names[j]][0]).next().is_none() &&
                    roads[&names[i]][1].intersection(&roads[&names[j]][1]).next().is_none()) {
                    same_level.unite(i, j);
                }
            }
        }
        for i in 0 .. names.len() {
            let root = same_level.find(i);
            if root == i { continue; }
            let mut relation = roads.get_mut(&names[i]).unwrap().drain(..).collect::<Vec<_>>();
            roads.remove(&names[i]);
            for (j, mut set) in relation.drain(..).enumerate() {
                for name in set.drain() {
                    roads.get_mut(&names[root]).unwrap()[j].insert(name);
                }
            }
        }
        println!("{}", indices.len());
        read!(m: usize);
        for _ in 0 .. m {
            read!(query: String);
            let pair = query.split('-').map(|name| name.to_owned()).filter(|name| indices.contains_key(name)).map(|name| same_level.find(indices[&name])).collect::<Vec<_>>();
            if pair.len() == 2{
                let from = pair[0];
                let to = pair[1];
                let mut depth = vec![-1; indices.len()];
                let mut stack = Vec::new();
                depth[from] = 0;
                stack.push(from);
                while let Some(top) = stack.pop() {
                    if depth[to] >= 0 {break;}
                    for name in & roads[&names[top]][1] {
                        let i = same_level.find(indices[name]);
                        if depth[i] >= 0{continue;}
                        stack.push(i);
                        depth[i] = depth[top] + 1;
                    }
                }
                if depth[to] >= 0 && (depth[from] ^ depth[to]) & 1 == 1 {
                    println!("YES");
                }else {
                    println!("NO");
                }
            }else {
                println!("NO");
            }
        }
    }
}