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.Collections.Generic;
using System.Linq;
using System.IO;
using SB = System.Text.StringBuilder;
//using System.Threading.Tasks;
//using System.Text.RegularExpressions;
//using System.Globalization;
//using System.Diagnostics;
using static System.Console;
using System.Numerics;
using static System.Math;
using pair = Pair<int, int>;

class Program
{
    static void Main()
    {
        SetOut(new StreamWriter(OpenStandardOutput()) { AutoFlush = false });
        new Program().solve();
        Out.Flush();
    }
    readonly Scanner cin = new Scanner();
    readonly int[] dd = { 0, 1, 0, -1, 0 }; //→↓←↑
    readonly int mod = 1000000007;
    readonly int dom = 998244353;
    bool chmax<T>(ref T a, T b) where T : IComparable<T> { if (a.CompareTo(b) < 0) { a = b; return true; } return false; }
    bool chmin<T>(ref T a, T b) where T : IComparable<T> { if (b.CompareTo(a) < 0) { a = b; return true; } return false; }

    void solve()
    {
        int N = cin.nextint;
        var T = new HLTree(N);
        for (int i = 0; i < N; i++)
        {
            var A = cin.scanint;
            for (int j = 1; j < A.Length; j++)
            {
                T.AddEdge(i, A[j]);
            }
        }
        T.Build();
        int Q = cin.nextint;
        for (int i = 0; i < Q; i++)
        {
            WriteLine(T.GetLCA(cin.nextint, cin.nextint));
        }

    }
}

/// <OriginalAuthor>camypaper</OriginalAuthor>
class HLTree
{
    readonly int n;
    readonly List<int>[] G;
    readonly int[] subtreeSize;
    readonly int[] maxsize;
    readonly int[] par;
    readonly int[] depth;
    readonly Chain[] go;
    readonly int[] pos;
    List<Chain> chains;
    public HLTree(int N)
    {
        n = N;
        G = new List<int>[n];
        chains = new List<Chain>();
        for (int i = 0; i < n; i++)
            G[i] = new List<int>();
        subtreeSize = new int[n];
        maxsize = new int[n];
        par = new int[n];
        depth = new int[n];
        go = new Chain[n];
        pos = new int[n];
    }
    public void AddEdge(int u, int v)
    {
        G[u].Add(v); G[v].Add(u);
    }
    public void Build(int root = 0)
    {
        computeSubtreeSize(root);
        Decomposite(-1, root, 0);
    }
    void computeSubtreeSize(int r)
    {
        var stack = new Stack<int>();
        stack.Push(r);
        var iter = new int[n];
        par[r] = -1;
        //dfs
        while (stack.Count > 0)
        {
            var cur = stack.Peek();
            if (iter[cur] == G[cur].Count)
            {
                stack.Pop();
                subtreeSize[cur]++;
                if (par[cur] != -1)
                {
                    subtreeSize[par[cur]] += subtreeSize[cur];
                    maxsize[par[cur]] = Math.Max(maxsize[par[cur]], subtreeSize[cur]);
                }
                continue;
            }
            var next = G[cur][iter[cur]++];
            if (next == par[cur]) continue;
            par[next] = cur;
            depth[next] = depth[cur] + 1;
            stack.Push(next);
        }
    }
    void Decomposite(int from, int cur, int lv)
    {
        var chain = new Chain(from, lv);
        chains.Add(chain);
        chain.Add(cur);
        while (cur != from)
        {
            var next = cur;
            go[cur] = chain;
            pos[cur] = chain.Count;
            foreach (var to in G[cur])
            {
                if (to == from) continue;
                if (maxsize[cur] == subtreeSize[to])
                {
                    maxsize[cur] = -1;
                    next = to;
                    chain.Add(to);
                }
                else Decomposite(cur, to, lv + 1);
            }

            from = cur;
            cur = next;

        }
        chain.Init();
    }
    // 頂点aから頂点bへの距離は depth(a) + depth(b) - 2 * depth(lca(a, b))
    public int GetLCA(int u, int v)
    {
        while (go[u] != go[v])
        {
            if (go[u].Level < go[v].Level) v = go[v].From;
            else u = go[u].From;
        }
        if (depth[u] <= depth[v]) return u;
        else return v;
    }
    public int this[int u]
    {
        get { return depth[u]; }
    }
}

class Chain
{
    public int From { get; set; }
    public int Level { get; set; }
    public int Count { get; private set; }
    List<int> heavy;
    public Chain(int from, int lv)
    {
        From = from;
        Level = lv;
        heavy = new List<int>();
    }
    public void Add(int v)
    {
        //heavy.Add(v);
        Count++;
    }
    public void Init()
    {

    }
}

static class Ex
{
    public static void join<T>(this IEnumerable<T> values, string sep = " ") => WriteLine(string.Join(sep, values));
    public static string concat<T>(this IEnumerable<T> values) => string.Concat(values);
    public static string reverse(this string s) { var t = s.ToCharArray(); Array.Reverse(t); return t.concat(); }

    public static int lower_bound<T>(this IList<T> arr, T val) where T : IComparable<T>
    {
        int low = 0, high = arr.Count;
        int mid;
        while (low < high)
        {
            mid = ((high - low) >> 1) + low;
            if (arr[mid].CompareTo(val) < 0) low = mid + 1;
            else high = mid;
        }
        return low;
    }
    public static int upper_bound<T>(this IList<T> arr, T val) where T : IComparable<T>
    {
        int low = 0, high = arr.Count;
        int mid;
        while (low < high)
        {
            mid = ((high - low) >> 1) + low;
            if (arr[mid].CompareTo(val) <= 0) low = mid + 1;
            else high = mid;
        }
        return low;
    }
}

class Pair<T, U> : IComparable<Pair<T, U>> where T : IComparable<T> where U : IComparable<U>
{
    public T f; public U s;
    public Pair(T f, U s) { this.f = f; this.s = s; }
    public int CompareTo(Pair<T, U> a) => f.CompareTo(a.f) != 0 ? f.CompareTo(a.f) : s.CompareTo(a.s);
    public override string ToString() => $"{f} {s}";
}

class Scanner
{
    string[] s; int i;
    readonly char[] cs = new char[] { ' ' };
    public Scanner() { s = new string[0]; i = 0; }
    public string[] scan => ReadLine().Split();
    public int[] scanint => Array.ConvertAll(scan, int.Parse);
    public long[] scanlong => Array.ConvertAll(scan, long.Parse);
    public double[] scandouble => Array.ConvertAll(scan, double.Parse);
    public string next
    {
        get
        {
            if (i < s.Length) return s[i++];
            string st = ReadLine();
            while (st == "") st = ReadLine();
            s = st.Split(cs, StringSplitOptions.RemoveEmptyEntries);
            i = 0;
            return next;
        }
    }
    public int nextint => int.Parse(next);
    public long nextlong => long.Parse(next);
    public double nextdouble => double.Parse(next);
}