Graph · 33 of 43
Oliver and the Game
Answer many questions of the form: is this house on the road between that house and the castle, in a town whose roads form a tree.
- Simple way
- time O(N * Q)
room O(N) - Clever way
- time O(N + Q)
room O(N)
The problem, simply
A town has N houses joined by N - 1 roads, so there is exactly one way between any two houses. House 1 is the King's castle. Bob hides in house X. Oliver starts at house Y.
Each question has a type. Type 0: Oliver walks from Y toward the castle. Type 1: Oliver walks from Y away from the castle (he may pick any branch). Answer YES if Oliver can find Bob, otherwise NO. Answer Q such questions.
In tree words: type 0 asks "is X on the path from Y up to the root?", which means X is an ancestor of Y (or the same house). Type 1 asks "is X somewhere below Y?", which means Y is an ancestor of X.
A story to remember it
Picture it
Nine houses. The castle, house 1, is at the top. Going up means going toward the castle. House 2 is above 6, 7, 8 and 9. House 3 is above 4 and 5.
- path
Examples
Walking toward the castle
- In
type 0, X = 2, Y = 8- Out
YES
From 8 Oliver walks 8, 7, 2, 1. He passes house 2, where Bob hides.
Walking the wrong way
- In
type 1, X = 2, Y = 8- Out
NO
House 8 has nothing below it, so walking away from the castle from 8 goes nowhere.
Different branches
- In
type 0, X = 6, Y = 5- Out
NO
From 5 Oliver walks 5, 3, 1. House 6 is on the other branch.
From the castle outward
- In
type 1, X = 9, Y = 1- Out
YES
Every house is below the castle, so Oliver can walk down to 9.
Same house
- In
type 0, X = 4, Y = 4- Out
YES
Oliver starts right where Bob hides. Make sure your check uses "at most" and not "less than".
Way 1: the simple way
Write down each house's parent (the next house toward the castle). For each question, climb from the lower house toward the castle and see if you meet the other house.
- Walk the tree once from house 1 and store
parent[v]for every house. - For type 0, climb from
Y. For type 1, climb fromX. - If the climb meets the other house, answer YES. If it passes the castle, answer NO.
class OliverClimb {
public static List<String> solve(int n, int[][] roads, int[][] queries) {
List<List<Integer>> adj = new ArrayList<>();
for (int i = 0; i <= n; i++) adj.add(new ArrayList<>());
for (int[] r : roads) { adj.get(r[0]).add(r[1]); adj.get(r[1]).add(r[0]); }
int[] parent = new int[n + 1]; // parent of the castle stays 0
boolean[] seen = new boolean[n + 1];
Queue<Integer> line = new ArrayDeque<>();
line.add(1);
seen[1] = true;
while (!line.isEmpty()) {
int u = line.poll();
for (int v : adj.get(u)) {
if (!seen[v]) { seen[v] = true; parent[v] = u; line.add(v); }
}
}
List<String> answers = new ArrayList<>();
for (int[] q : queries) {
int type = q[0], x = q[1], y = q[2];
int top = type == 0 ? x : y; // the house that must be higher up
int cur = type == 0 ? y : x; // start climbing from the other one
boolean found = false;
while (cur != 0) {
if (cur == top) { found = true; break; }
cur = parent[cur];
}
answers.add(found ? "YES" : "NO");
}
return answers;
}
}How long it takes: one climb can pass every house when the tree is a long line, so Q questions cost O(N * Q). With N and Q both near 100,000 that is far too slow. Extra room: the parent array, O(N).
Way 2: the clever way
Stamp every house with an in time and an out time during one walk. A house A is above house B (or is B) exactly when in[A] <= in[B] and out[B] <= out[A]. The walk is a depth first search, and the stamps are called entry and exit times.
- Start a clock at 0. Walk from the castle. When you enter a house, write
inand tick the clock. - Visit every child fully before leaving. When you leave a house, write
outand tick the clock. - For type 0, answer
isAbove(X, Y). For type 1, answerisAbove(Y, X).
One walk stamps every house, then each question is four numbers
01 / 10
Enter the castle at time 0. It goes on the walk pile.
- clock
- 1
- looking now
- done
- answer
- rejected
- path
class OliverStamps {
static int[] in, out;
public static List<String> solve(int n, int[][] roads, int[][] queries) {
List<List<Integer>> adj = new ArrayList<>();
for (int i = 0; i <= n; i++) adj.add(new ArrayList<>());
for (int[] r : roads) { adj.get(r[0]).add(r[1]); adj.get(r[1]).add(r[0]); }
stamp(n, adj);
List<String> answers = new ArrayList<>();
for (int[] q : queries) {
int type = q[0], x = q[1], y = q[2];
boolean yes = type == 0 ? isAbove(x, y) : isAbove(y, x);
answers.add(yes ? "YES" : "NO");
}
return answers;
}
// a is b, or a is on the way from b up to the castle
static boolean isAbove(int a, int b) {
return in[a] <= in[b] && out[b] <= out[a];
}
// depth first walk with our own pile, so a long line of houses cannot overflow the call stack
static void stamp(int n, List<List<Integer>> adj) {
in = new int[n + 1];
out = new int[n + 1];
int[] parent = new int[n + 1];
int[] nextChild = new int[n + 1];
Deque<Integer> pile = new ArrayDeque<>();
int clock = 0;
pile.push(1);
in[1] = clock++;
while (!pile.isEmpty()) {
int u = pile.peek();
if (nextChild[u] < adj.get(u).size()) {
int v = adj.get(u).get(nextChild[u]++);
if (v == parent[u]) continue; // do not walk back up
parent[v] = u;
in[v] = clock++; // stamp on the way in
pile.push(v);
} else {
out[u] = clock++; // stamp on the way out
pile.pop();
}
}
}
}How long it takes: the walk touches every house and road once, O(N), and each question is four comparisons, O(1). Total O(N + Q). Extra room: the stamps, the parent array and the pile, O(N).
Watch out for
- Mixing up the two types. Type 0 checks
isAbove(X, Y), type 1 checksisAbove(Y, X). X == Ymust give YES. Use<=, not<.- The roads have no direction. Remember the parent, or a seen array, so the walk does not go back up.
- Reading input fast matters on this problem. Use a fast reader in Java.
What interviewers ask next
- Find the lowest common ancestor of two houses. If one is above the other, it is that one. Otherwise jump up with binary lifting until just below the meeting point,
O(log N)per question. - Count the houses in the part below
v, countingvitself. It is(out[v] - in[v] + 1) / 2with this clock, because each of those houses uses two ticks. - Add a value to every house below
v, or sum them. The houses belowvform one stretch of the in-time order, so a Fenwick tree or segment tree over that order works. - What if the roads can change? Then the stamps break. You need heavier tools like link-cut trees or an offline approach.
Remember this
Grown-up words: the town is a rooted tree, the castle is the root, "above" means ancestor, the stamps are entry and exit times (an Euler tour), and the walk pile is the DFS stack.