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: Time Limit Exceeded)

#include <stdio.h>

#define MAX_NODE (100000)
#define MAX_DEPTH (16)
#define MAX_PAIR (4096)

typedef struct _Pair{
    int source;
    int sink;
    int result;
} Pair;

int parent[MAX_NODE] = {0};
int so_list[MAX_NODE];
int si_list[MAX_NODE];
int so;
int si;
int tree_cache[MAX_NODE][MAX_DEPTH];
int t_size[MAX_NODE];

Pair _pair[MAX_NODE];
int _ps = 0;

void init_cache(int root, int n) {
    int i,j,node;
    for(i=0;i<n;i++) {
        t_size[i] = -1;
        tree_cache[i][0] = i;
        for(j=1;j<MAX_DEPTH;j++) {
            node = parent[tree_cache[i][j-1]];
            tree_cache[i][j] = node;
            if(node == root) {
                t_size[i] = j + 1;
                break;
            }
        }
    }
}

int binary_search(int left, int right, int* so, int* si, int root) {
    int i, node;
    int middle = (left + right) / 2;
    if(right - left < 40) {
        for(i=left,node=root;i<=right;i++) {
            if(so[i] == si[i]) {
                return so[i];
            }
        }
        return node;
    }
    
    if(so[middle] != si[middle]) {
        return binary_search(middle, right, so, si, root);
    }
    
    return binary_search(left, middle, so, si, root);
}

int solve(int source, int sink, int root) {
    int node;
    int last;
    int result;
    int i;
    int* p_so_list = so_list;
    int* p_si_list = si_list;
    if(source == sink) return source;
    so = si = 0;
    for(i=0;i<_ps;i++) {
        if(_pair[i].source == source && _pair[i].sink == sink) {
            return _pair[i].result;
        }
    }

    // sourceからrootへ行く際に通るnodeを登録
    if(t_size[source] == -1) {
        node = source;
        while(node != root) {
            so_list[so++] = node;
            node = parent[node];
        }
        so_list[so++] = node;
    } else {
        p_so_list = tree_cache[source];
        so = t_size[source];
    }

    // sinkからrootへ行く際に通るnodeを登録
    if(t_size[sink] == -1) {
        node = sink;
        while(node != root) {
            si_list[si++] = node;
            node = parent[node];
        }
        si_list[si++] = node;
    } else {
        p_si_list = tree_cache[sink];
        si = t_size[sink];
    }

    _pair[_ps].source = source;
    _pair[_ps].sink = sink;
    if(si > so) {
        last = si - so;
        return _pair[_ps++].result = binary_search(0, so, p_so_list, &p_si_list[last], root);
    }
    
    last = so - si;
    return _pair[_ps++].result = binary_search(0, si, &p_so_list[last], p_si_list, root);
    
}

int main(void) {
    int i, j, m, n, t, q;
    int source, sink;
    int is_root[MAX_NODE] = {0};
    int root;
    
    scanf("%d\n", &n);
    for(i=0;i<n;i++) {
        scanf("%d", &m);

        for(j=0;j<m;j++) {
            scanf("%d", &t);
            is_root[t] = -1;
            parent[t] = i;
        }
    }
    
    // ルート
    root = 0;
    for(i=0;i<n;i++) {
        if(is_root[i] == 0) {
            root = i;
            break;
        }
    }
	
	for(i=0;i<MAX_NODE;i++) {
		
	}
    
    // 浅いものはあらかじめ作っておく
    init_cache(root, n);
    
    scanf("%d\n", &q);
    for(i=0;i<q;i++) {
        scanf("%d %d\n" ,&source, &sink);
        printf("%d\n", solve(source, sink, root));
    }

    return 0;
}