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 HL = new HeavyLightDecomposition(N);
        for (int i = 0; i < N; i++)
        {
            int num = Reader.Int();
            for (int t = 0; t < num; t++)
                HL.AddEdge(i, Reader.Int());
        }
        int Q = Reader.Int();
        var table = Reader.IntTable(Q);
        HL.Build();
        Console.SetOut(new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = false });
        foreach (var q in table)
            Console.WriteLine(HL.LCA(q[0], q[1]));
        Console.Out.Flush();
    }

    class HeavyLightDecomposition
    {
        public readonly int N;
        List<int>[] E;
        int[] Y, X, Size, Parent;
        List<List<int>> Path; // debug
        List<int> PathDepth;

        public HeavyLightDecomposition(int n)
        {
            N = n;
            Y = new int[N]; X = new int[N];
            Size = new int[N]; Parent = new int[N];
            Path = new List<List<int>>();
            Path.Add(new List<int>());
            PathDepth = new List<int>();
            PathDepth.Add(0);
            E = new List<int>[N];
            for (int i = 0; i < N; i++) E[i] = new List<int>();
        }
        public void AddEdge(int a, int b)
        {
            E[a].Add(b);
            E[b].Add(a);
        }
        public void Build(int root = 0)
        {
            CountSize(root, -1);
            CompressPath(0, 0, 0);
        }
        int CountSize(int a, int parent)
        {
            Parent[a] = parent;
            Size[a] = 1;
            var e = E[a];
            for (int i = 0; i < e.Count; i++)
                if (e[i] == parent) { e.RemoveAt(i); i--; }
                else
                {
                    int size = CountSize(e[i], a);
                    Size[a] += size;
                    if (size > Size[e[0]]) { int t = e[0]; e[0] = e[i]; e[i] = t; }
                }
            return Size[a];
        }
        void CompressPath(int a, int pathId, int depth)
        {
            Y[a] = pathId;
            X[a] = Path[pathId].Count;
            Path[pathId].Add(a);
            if (E[a].Count == 0) return;
            CompressPath(E[a][0], pathId, depth);
            for (int i = 1; i < E[a].Count; i++)
            {
                Path.Add(new List<int>());
                PathDepth.Add(depth + 1);
                CompressPath(E[a][i], Path.Count - 1, depth + 1);
            }
        }

        public int LCA(int a, int b)
        {
            int pa = Y[a], pb = Y[b];
            if (pa == pb) return (X[a] < X[b]) ? a : b;
            if (PathDepth[pa] >= PathDepth[pb]) return LCA(Parent[Path[pa][0]], b);
            return LCA(a, Parent[Path[pb][0]]);
        }

    }

}

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;
    }
}