Problem:
LCA: Lowest Common Ancestor

For a rooted tree, find the lowest common ancestor of two nodes u and v.

The given tree consists of n nodes and every node has a unique ID from 0 to n-1 where 0 is the root.

Input

n
k0 c1 c2 ... ck0
k1 c1 c2 ... ck1
:
kn-1 c1 c2 ... ckn-1
q
u1 v1
u2 v2
:
uq vq

The first line of the input includes an integer n, the number of nodes of the tree.

In the next n lines, the information of node i is given. ki is the number of children of node i, and c1, ... cki are node IDs of 1st, ... kth child of node i.

In the next line, the number of queryies q is given. In the next q lines, pairs of u and v are given as the queries.

Output

For each query, print the LCA of u and v in a line.

Constraints

1 ≤ n ≤ 100000

1 ≤ q ≤ 100000

Sample Input 1

8
3 1 2 3
2 4 5
0
0
0
2 6 7
0
0
4
4 6
4 7
4 3
5 2

Sample Output 1

1
1
0
0

Solution in C# (judge verdict: Accepted)

using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.Diagnostics;
using Enu = System.Linq.Enumerable;

public class Program
{
    public void Solve()
    {
        int N = Reader.Int();
        var E = new List<int>[N];

        for (int i = 0; i < N; i++)
        {
            E[i] = new List<int>();
            int num = Reader.Int();
            for (int t = 0; t < num; t++)
                E[i].Add(Reader.Int());
        }
        int Q = Reader.Int();
        var table = Reader.IntTable(Q);
        var lca = new LowestCommonAncestor(0, E);
        Console.SetOut(new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = false });
        foreach (var q in table)
            Console.WriteLine(lca.Get(q[0], q[1]));
        Console.Out.Flush();
    }

    class LowestCommonAncestor
    {
        List<int>[] G;
        RangeMinQueryIndex Rmq;
        List<int> Vs = new List<int>();
        List<int> Depth = new List<int>();
        int[] Id;

        public LowestCommonAncestor(int root, List<int>[] G)
        {
            this.G = G;
            Init(root);
        }
        public int Get(int a, int b)
        {
            int L = Math.Min(Id[a], Id[b]);
            int R = Math.Max(Id[a], Id[b]) + 1;
            int i = Rmq.Get(L, R);
            return Vs[i];
        }
        private void Init(int root)
        {
            Id = new int[G.Length];
            DFS(root, -1, 0);
            Rmq = new RangeMinQueryIndex(Depth.Count);
            for (int i = 0; i < Depth.Count; i++)
                Rmq.Set(i, Depth[i]);
        }
        private void DFS(int v, int prev, int d)
        {
            Id[v] = Vs.Count;
            Vs.Add(v);
            Depth.Add(d);
            foreach (int next in G[v])
                if (next != prev)
                {
                    DFS(next, v, d + 1);
                    Vs.Add(v);
                    Depth.Add(d);
                }
        }
    }

    class RangeMinQueryIndex
    {
        private static readonly int INF = (int)1e9;
        public readonly int N;
        private readonly int[] tree;
        private readonly int[] index;

        public RangeMinQueryIndex(int N)
        {
            while (N < 2 || (N & (N - 1)) != 0) { N += N & -N; }
            this.N = N;
            tree = new int[N * 2];
            index = new int[N * 2];
            for (int i = 0; i < tree.Length; i++) tree[i] = INF;
        }
        public void Set(int i, int val)
        {
            int id = i;
            i += N - 1;
            tree[i] = val;
            index[i] = id;
            while (i > 0)
            {
                i = (i - 1) / 2;
                int L = i * 2 + 1, R = i * 2 + 2;
                if (tree[L] <= tree[R]) { tree[i] = tree[L]; index[i] = index[L]; }
                else { tree[i] = tree[R]; index[i] = index[R]; }
            }
        }
        // [L, R)
        public int Get(int L, int R) { int v = -1; return Rec(0, ref v, 0, N, L, R); }
        private int Rec(int i, ref int val, int currL, int currR, int L, int R)
        {
            if (currL >= R || currR <= L) { val = INF; return -1; }
            if (currL >= L && currR <= R) { val = tree[i]; return index[i]; }
            int mid = (currL + currR) / 2;
            int Lv = INF, Rv = INF;
            int Li = Rec(i * 2 + 1, ref Lv, currL, mid, L, R);
            int Ri = Rec(i * 2 + 2, ref Rv, mid, currR, L, R);
            if (Lv <= Rv) { val = Lv; return Li; }
            val = Rv; return Ri;
        }
    }
}

class Entry { static void Main() { new Program().Solve(); } }
class Reader
{
    static TextReader reader = Console.In;
    static readonly char[] separator = { ' ' };
    static readonly StringSplitOptions op = StringSplitOptions.RemoveEmptyEntries;
    static string[] A = new string[0];
    static int i;
    static void Init() { A = new string[0]; }
    public static void Set(TextReader r) { reader = r; Init(); }
    public static void Set(string file) { reader = new StreamReader(file); Init(); }
    public static bool HasNext() { return CheckNext(); }
    public static string String() { return Next(); }
    public static int Int() { return int.Parse(Next()); }
    public static long Long() { return long.Parse(Next()); }
    public static double Double() { return double.Parse(Next()); }
    public static int[] IntLine() { return Array.ConvertAll(Split(Line()), int.Parse); }
    public static int[] IntArray(int N) { return Range(N, Int); }
    public static int[][] IntTable(int H) { return Range(H, IntLine); }
    public static string[] StringArray(int N) { return Range(N, Next); }
    public static string[][] StringTable(int N) { return Range(N, () => Split(Line())); }
    public static string Line() { return reader.ReadLine().Trim(); }
    static string[] Split(string s) { return s.Split(separator, op); }
    static T[] Range<T>(int N, Func<T> f) { var r = new T[N]; for (int i = 0; i < N; r[i++] = f()); return r; }
    static string Next() { CheckNext(); return A[i++]; }
    static bool CheckNext()
    {
        if (i < A.Length) return true;
        string line = reader.ReadLine();
        if (line == null) return false;
        if (line == "") return CheckNext();
        A = Split(line);
        i = 0;
        return true;
    }
}