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.Linq;//リストの使用
using System.Collections.Generic;
using System.Text;//テキストの高速出力に必要
class Program
{
static int n = int.Parse(Console.ReadLine());
static List<int>[] nextList = new List<int>[n];
static List<int>[] childrenList = new List<int>[n];
static int[] depths = new int[n];//木の深さ

	static void Main()
	{
    for(int i = 0; i < n; i++)
    {
      childrenList[i] = new List<int>();
      int[] nums = Array.ConvertAll(Console.ReadLine().Split(' '),int.Parse);
      for(int j = 0; j < nums[0]; j++)
      {
        childrenList[i].Add(nums[j+1]);
      }
    }

    int[] vertexParents = VertexParents();
    SearchDepths(0,0);
    int[,] treeParents = TreeParents(0,vertexParents);
    
    int q = int.Parse(Console.ReadLine());

    for(int i = 0; i < q; i++)
    {
      int[] numsa = Array.ConvertAll(Console.ReadLine().Split(' '),int.Parse);
      Console.WriteLine(LowestCommonAncester(treeParents,numsa[0],numsa[1]));
    }
	}

  static void MakeChildrenList(int rootNum)
  {//nextListからchildrenListを、引数を0-indexの根の番号としてO(頂点数)で作る
    for(int i = 0; i < nextList[rootNum].Count(); i++)
    {
      childrenList[rootNum].Add(nextList[rootNum][i]);
      nextList[nextList[rootNum][i]].Remove(rootNum);//木の逆走を防ぐ
      MakeChildrenList(nextList[rootNum][i]);
    }
  }

  static int[] VertexParents()
  {//頂点数nとchildrenListから、各頂点の親（根は-1）をO(n)で返す
    int[] answers = new int[n];
    for(int i = 0; i < n; i++) answers[i] = -1;

    for(int i = 0; i < n; i++)
    {
      for(int j = 0; j < childrenList[i].Count; j++)
      {
        answers[childrenList[i][j]] = i;
      }
    }

    return answers;
  }

  static void SearchDepths(int vertexNum, int depth)
  {//頂点数nとchildrenListから、引数の頂点の深さ及び、その子の深さをO(頂点数)で設定
    depths[vertexNum] = depth;//深さを設定

    for(int i = 0; i < childrenList[vertexNum].Count; i++)
    {
      SearchDepths(childrenList[vertexNum][i],depth+1);//子の深さを設定
    }
  }

  static int[,] TreeParents(int rootVertex, int[] parents)
  {//頂点数n、0-indexで根の番号、各頂点の親（根は-1）として、
  //O(nlogn)で2^i個上の親を返す。いない場合は-1。
    int[,] answers = new int[n,24];
    for(int i = 0; i < n; i++)
    {
      for(int j = 0; j < 24; j++)
      {
        answers[i,j] = -1;
      }
    }
    for(int i = 0; i < n; i++) answers[i,0] = parents[i];

    for(int i = 1; i < 24; i++)
    {
      for(int j = 0; j < n; j++)
      {
        if(answers[j,i-1] != -1) answers[j,i] = answers[answers[j,i-1],i-1];
        else answers[j,i] = -1;
      }
    }
    
    return answers;
  }

  static int SearchParent(int[,] treeParents, int vertexNum, int parentCount)
  {//TreeParents()で求めた親から、引数の頂点からparentCountだけ上の親番号をO(log頂点数)で返す。
    if(vertexNum == -1) return -1;
  
    for(int i = 0; i < 24; i++)
    {
      if((parentCount & (1<<i)) != 0) vertexNum = treeParents[vertexNum,i];
      if(vertexNum == -1) return -1;
    }
    return vertexNum;
  }

  static int LowestCommonAncester(int[,] treeParents, int vertexA, int vertexB)
  {//TreeParents()で求めた親とdepthsから、2頂点の最小共通祖先をO((log頂点数)^2)で返す。
    if(depths[vertexA] > depths[vertexB])
      vertexA = SearchParent(treeParents, vertexA, depths[vertexA]-depths[vertexB]);
    else if(depths[vertexA] < depths[vertexB])
      vertexB = SearchParent(treeParents, vertexB, depths[vertexB]-depths[vertexA]);

    return (SearchParent(treeParents, vertexA, SearchAncester(0,1<<23,-1,treeParents,vertexA,vertexB)));
  }

  static int SearchAncester(int min, int max, int MinorMax,
    int[,] treeParents, int vertexA, int vertexB)//二分探索法で最小値-1最大値1を求める
  {
    while (true)
    {
      int mid = min + (max - min) / 2;
      if(MinorMax == 1)
      {
        if(CheckAncester(mid,treeParents,vertexA,vertexB)) min = mid;//さらに大きくても成り立つかも
        else max = mid;
      }else
      {
        if(CheckAncester(mid,treeParents,vertexA,vertexB)) max = mid;//さらに小さくても成り立つかも
        else min = mid;
      }

      if(max - min <= 1)
      {
        if(MinorMax == 1)
        {
          if(CheckAncester(max,treeParents,vertexA,vertexB)) return max;//最大値で成り立つかの確認を優先
          else return min;
        }else
        {
          if(CheckAncester(min,treeParents,vertexA,vertexB)) return min;//最小値で成り立つかの確認を優先
          else return max;
        }

      break;
      }  
    }
  }

  static bool CheckAncester(int testNum, int[,] treeParents, int vertexA, int vertexB)
  {
    if(SearchParent(treeParents,vertexA,testNum) != SearchParent(treeParents,vertexB,testNum)
      && SearchParent(treeParents,vertexA,testNum) != -1) return false;

    return true;
  }  

  
}