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



Sample input:
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
0
0

Submission status: Accepted

Solution code:
import sys
if sys.version[0] == '2':
    range, input = xrange, raw_input


class HeavyLightDecomposition:
    def __init__(self, g, root=0):
        self.g = g
        self.vid, self.head, self.heavy, self.parent = [0] * len(g), [-1] * len(g), [-1] * len(g), [-1] * len(g)
        self.dfs(root)
        self.bfs(root)

    def dfs(self, root):
        stack = [(root, -1, False)]
        sub, max_sub = [1] * len(self.g), [(0, -1)] * len(self.g)
        while stack:
            v, par, flag = stack.pop()
            if not flag:
                self.parent[v] = par
                stack.append((v, par, True))
                stack.extend((c, v, False) for c in self.g[v] if c != par)
            else:
                if par != -1:
                    sub[par] += sub[v]
                    max_sub[par] = max(max_sub[par], (sub[v], v))
                self.heavy[v] = max_sub[v][1]

    def bfs(self, root=0):
        from collections import deque
        k, que = 0, deque([root])
        while que:
            r = v = que.popleft()
            while v != -1:
                self.vid[v], self.head[v] = k, r
                for c in self.g[v]:
                    if c != self.parent[v] and c != self.heavy[v]:
                        que.append(c)
                k += 1
                v = self.heavy[v]

    def lca(self, u, v):
        while self.head[u] != self.head[v]:
            if self.vid[u] > self.vid[v]:
                u, v = v, u
            v = self.parent[self.head[v]]
        else:
            if self.vid[u] > self.vid[v]:
                u, v = v, u
        return u

N = int(input())
g = [[] for _ in range(N)]
for i in range(N):
    for c in map(int, input().split()[1:]):
        g[i].append(c)
        g[c].append(i)
hld = HeavyLightDecomposition(g)
Q = int(input())
for _ in range(Q):
    u, v = map(int, input().split())
    print(hld.lca(u, v))

Submission status: Accepted

Solution code:
import sys
if sys.version[0] == '2':
    range, input = xrange, raw_input


class HeavyLightDecomposition:
    def __init__(self, g, root=0):
        self.g = g
        self.vid, self.head, self.heavy, self.parent = [0] * len(g), [-1] * len(g), [-1] * len(g), [-1] * len(g)
        self.dfs(root)
        self.bfs(root)

    def dfs(self, root):
        stack = [(root, -1, False)]
        sub, max_sub = [1] * len(self.g), [(0, -1)] * len(self.g)
        while stack:
            v, par, flag = stack.pop()
            if not flag:
                self.parent[v] = par
                stack.append((v, par, True))
                stack.extend((c, v, False) for c in self.g[v] if c != par)
            else:
                if par != -1:
                    sub[par] += sub[v]
                    if sub[v] > max_sub[par][0]:
                        max_sub[par] = max(max_sub[par], (sub[v], v))
                self.heavy[v] = max_sub[v][1]

    def bfs(self, root=0):
        from collections import deque
        k, que = 0, deque([root])
        while que:
            r = v = que.popleft()
            while v != -1:
                self.vid[v], self.head[v] = k, r
                for c in self.g[v]:
                    if c != self.parent[v] and c != self.heavy[v]:
                        que.append(c)
                k += 1
                v = self.heavy[v]

    def lca(self, u, v):
        while self.head[u] != self.head[v]:
            if self.vid[u] > self.vid[v]:
                u, v = v, u
            v = self.parent[self.head[v]]
        else:
            if self.vid[u] > self.vid[v]:
                u, v = v, u
        return u

N = int(input())
g = [[] for _ in range(N)]
for i in range(N):
    for c in map(int, input().split()[1:]):
        g[i].append(c)
        g[c].append(i)
hld = HeavyLightDecomposition(g)
Q = int(input())
for _ in range(Q):
    u, v = map(int, input().split())
    print(hld.lca(u, v))

Submission status: Accepted

Solution code:
import sys
if sys.version[0] == '2':
    range, input = xrange, raw_input


class HeavyLightDecomposition:
    def __init__(self, g, root=0):
        self.g = g
        self.vid, self.head, self.heavy, self.parent = [0] * len(g), [-1] * len(g), [-1] * len(g), [-1] * len(g)
        self.dfs(root)
        self.bfs(root)

    def dfs(self, root):
        stack = [(root, -1)]
        sub, max_sub = [1] * len(self.g), [(0, -1)] * len(self.g)
        used = [False] * len(self.g)
        while stack:
            v, par = stack.pop()
            if not used[v]:
                self.parent[v] = par
                used[v] = True
                stack.append((v, par))
                stack.extend((c, v) for c in self.g[v] if c != par)
            else:
                if par != -1:
                    sub[par] += sub[v]
                    if sub[v] > max_sub[par][0]:
                        max_sub[par] = max(max_sub[par], (sub[v], v))
                self.heavy[v] = max_sub[v][1]

    def bfs(self, root=0):
        from collections import deque
        k, que = 0, deque([root])
        while que:
            r = v = que.popleft()
            while v != -1:
                self.vid[v], self.head[v] = k, r
                for c in self.g[v]:
                    if c != self.parent[v] and c != self.heavy[v]:
                        que.append(c)
                k += 1
                v = self.heavy[v]

    def lca(self, u, v):
        while self.head[u] != self.head[v]:
            if self.vid[u] > self.vid[v]:
                u, v = v, u
            v = self.parent[self.head[v]]
        else:
            if self.vid[u] > self.vid[v]:
                u, v = v, u
        return u

N = int(input())
g = [[] for _ in range(N)]
for i in range(N):
    for c in map(int, input().split()[1:]):
        g[i].append(c)
        g[c].append(i)
hld = HeavyLightDecomposition(g)
Q = int(input())
for _ in range(Q):
    u, v = map(int, input().split())
    print(hld.lca(u, v))

Submission status: Accepted

Solution code:
from math import log2


def build():
    dfs()
    pk0 = parent[0]
    for k in range(1, logn):
        pk1 = parent[k]
        for v in range(n):
            pkv = pk0[v]
            pk1[v] = -1 if pkv < 0 else pk0[pkv]
        pk0 = pk1


def dfs():
    stack = [(0, -1, 0)]
    while stack:
        v, p, d = stack.pop()
        parent[0][v] = p
        depth[v] = d
        stack.extend((child, v, d + 1) for child in tree[v])


def get(u, v):
    du, dv = depth[u], depth[v]
    if du > dv:
        u, v = v, u
        du, dv = dv, du
    for k in range(logn):
        if (dv - du) >> k & 1:
            v = parent[k][v]
    if u == v:
        return u
    for k in range(logn - 1, -1, -1):
        pk = parent[k]
        if pk[u] != pk[v]:
            u, v = pk[u], pk[v]
    return parent[0][u]


n = int(input())
tree = [set(map(int, input().split()[1:])) for _ in range(n)]

logn = int(log2(n)) + 1
parent = [[0] * n for _ in range(logn)]
depth = [0] * n
build()

q = int(input())
for _ in range(q):
    print(get(*map(int, input().split())))

Submission status: Accepted

Solution code:
from math import log2


def build():
    dfs()
    pk0 = parent[0]
    for pk1 in parent[1:]:
        for v in range(n):
            pkv = pk0[v]
            pk1[v] = -1 if pkv < 0 else pk0[pkv]
        pk0 = pk1


def dfs():
    stack = [(0, -1, 0)]
    while stack:
        v, p, d = stack.pop()
        parent[0][v] = p
        depth[v] = d
        stack.extend((child, v, d + 1) for child in tree[v])


def get(u, v):
    du, dv = depth[u], depth[v]
    if du > dv:
        u, v = v, u
        du, dv = dv, du
    for k, pk in enumerate(parent):
        if (dv - du) >> k & 1:
            v = pk[v]
    if u == v:
        return u
    for pk in parent[logn - 1:None:-1]:
        pku, pkv = pk[u], pk[v]
        if pku != pkv:
            u, v = pku, pkv
    return parent[0][u]


n = int(input())
tree = [set(map(int, input().split()[1:])) for _ in range(n)]

logn = int(log2(n)) + 1
parent = [[0] * n for _ in range(logn)]
depth = [0] * n
build()

q = int(input())
for _ in range(q):
    print(get(*map(int, input().split())))

Submission status: Accepted

Solution code:
from collections import deque
n = input()

C = [None]*n
P = [None]*n
for i in xrange(n):
    ipt = map(int, raw_input().split())
    C[i] = ipt[1:]
    for c in C[i]:
        P[c] = i
LEV = (n+1).bit_length()
parent = [[None]*(LEV + 1) for i in xrange(n)]
for i in xrange(n):
    parent[i][0] = P[i]
for k in xrange(LEV):
    for i in xrange(n):
        if parent[i][k] is None:
            parent[i][k+1] = None
        else:
            parent[i][k+1] = parent[parent[i][k]][k]
depth = [None]*n
deq = deque()
deq.append(0)
depth[0] = 0
while deq:
    v = deq.popleft()
    for c in C[v]:
        deq.append(c)
        depth[c] = depth[v] + 1

q = input()
for t in xrange(q):
    u, v = map(int, raw_input().split())
    if not depth[u] < depth[v]:
        u, v = v, u
    for k in xrange(LEV+1):
        if ((depth[v] - depth[u]) >> k) & 1:
            v = parent[v][k]
    if u == v:
        print u
        continue

    for k in xrange(LEV, -1, -1):
        if parent[u][k] != parent[v][k]:
            u = parent[u][k]
            v = parent[v][k]
    print parent[u][0]

Submission status: Accepted

Solution code:
import math
import sys
from collections import defaultdict
sys.setrecursionlimit(200000)

def dfs(here, p, d, parent, depth, connect):
    parent[0][here] = p
    depth[here] = d
    for next_v in connect[here]:
        dfs(next_v, here, d + 1, parent, depth, connect)

def lca(v1, v2, parent, depth):
    if depth[v2] > depth[v1]:
        v1, v2 = v2, v1
    for i in range(max_log):
        if depth[v1] - depth[v2] >> i & 1:
            v1 = parent[i][v1]
    if v1 == v2:
        return v2
    for i in range(max_log - 1, -1, -1):
        if parent[i][v1] != parent[i][v2]:
            v1 = parent[i][v1]
            v2 = parent[i][v2]
    return parent[0][v1]

connect = defaultdict(list)
v_num = int(input())
root = 0
for i in range(v_num):
    edge = [int(n) for n in input().split(" ")]
    connect[i].extend(edge[1:])
depth = [-1 for n in range(v_num)]
max_log = max(int(math.log(v_num, 2)), 1)
parent = [[-1 for n in range(v_num)] for m in range(max_log)]
dfs(root, -1, 0, parent, depth, connect)
for i in range(max_log - 1):
    for v in range(v_num):
        parent[i + 1][v] = -1 if parent[i][v] < 0 else parent[i][parent[i][v]]
q_num = int(input())
for _ in range(q_num):
    v1, v2 = (int(n) for n in input().split(" ") )
    print(lca(v1, v2, parent, depth))

Submission status: Accepted

Solution code:
#fake answer?

import math
import sys
from collections import defaultdict
sys.setrecursionlimit(200000)

def dfs(here, p, d, parent, depth, connect):
    parent[0][here] = p
    depth[here] = d
    for next_v in connect[here]:
        dfs(next_v, here, d + 1, parent, depth, connect)

def lca(v1, v2, parent, depth):
    if depth[v2] > depth[v1]:
        v1, v2 = v2, v1
    for i in range(max_log):
        if depth[v1] - depth[v2] >> i & 1:
            v1 = parent[i][v1]
    if v1 == v2:
        return v2
    for i in range(max_log - 1, -1, -1):
        if parent[i][v1] != parent[i][v2]:
            v1 = parent[i][v1]
            v2 = parent[i][v2]
    return parent[0][v1]

connect = defaultdict(list)
v_num = int(input())
root = 0
for i in range(v_num):
    edge = [int(n) for n in input().split(" ")]
    connect[i].extend(edge[1:])
depth = [-1 for n in range(v_num)]
max_log = max(int(math.log(v_num, 2)), 1)
parent = [[-1 for n in range(v_num)] for m in range(max_log)]
dfs(root, -1, 0, parent, depth, connect)
for i in range(max_log - 1):
    for v in range(v_num):
        parent[i + 1][v] = -1 if parent[i][v] < 0 else parent[i][parent[i][v]]
q_num = int(input())
for _ in range(q_num):
    v1, v2 = (int(n) for n in input().split(" ") )
    print(lca(v1, v2, parent, depth))

Submission status: Accepted

Solution code:
import math
import sys
import resource
MAX_N = 202020
sys.setrecursionlimit(MAX_N)
E = [[] for i in range(MAX_N)]
depth = [0]*MAX_N
K = (int)(math.log2(MAX_N) + 10)

#db[i][j] = 頂点jの2^i個上の頂点
#iは高々、log2(頂点数)の切り上げを超えない。(このコードでは念のため少し余裕を持たせている。)
db = [[-1]*(MAX_N) for i in range(K)] 

#根からの深さを記録するためのdfs
def dfs(now,parent,d):
    #nowの2^0(=1)個上は、親頂点である。
    db[0][now] = parent
    depth[now] = d
    for to in E[now]:
        if(to != parent):dfs(to,now,d+1)

#ダブリング
def doubling():
    for i in range(K-1):
        for j in range(MAX_N):
            if(db[i][j] < 0):
                #頂点jの2^i個上が-1→jの2^i個上は根を飛び越えてしまっているので、2^(i+1) 個上も当然根を飛び越えている。
                db[i+1][j] = -1
            else:
                #頂点jの2^i個上がdb[i][j]→頂点jの2^(i+1) 個次の頂点は、「jの2^i個次の頂点」の「2^i個次の頂点」である。
                db[i+1][j] = db[i][db[i][j]]

def LCA(u,v):
    #uのほうが浅い場合は、swapする。(これにより、一般性を失わずuを深いほうにできる。)
    if(depth[u] < depth[v]):u,v = v,u
    if(u == v):return u

    

    #uとvについて、根からの距離をそろえる
    #iの降順に見ていっていることに注意
    #uの2^i個上がまだvの深さ以上の場合、2^i個さかのぼる
    for i in range(K-1,-1,-1):
        if(db[i][u] == -1):continue
        if(depth[db[i][u]] >= depth[v]):u = db[i][u]
    #この時点でuとvの深さは等しい。
    if(u == v):return u

    #u,vの2^i個上の頂点について、等しいなら2^i個さかのぼり、そうでないならとどまる、という動きの繰り返し
    #iの降順に見ていっていることに注意
    for i in range(K-1,-1,-1):
        if(db[i][u] != db[i][v]):
            u = db[i][u]
            v = db[i][v]
    #上り終わった後のuの親がLCAとなっている。
    return db[0][u]
    



n = int(input())
for i in range(n):
    li = list(map(int,input().split()))
    for j in range(li[0]):E[i].append(li[j+1])

dfs(0,-1,0)
doubling()

q = int(input())
for i in range(q):
    u,v =li = list(map(int,input().split()))
    print(LCA(u,v))

Submission status: Accepted

Solution code:
import math

def lca(x, y):
    if d[x] < d[y]:
        x,y = y,x
    dy = d[y]
    k = d[x]-dy#abs(depth)
    #Align depth
    while k:
        x = p[x][int(math.log(k,2))]
        k = d[x]-dy

    if x == y:
        return x

    for i in range(h)[::-1]:
        #print(h)
        if p[x][i] != p[y][i]:
            x = p[x][i]
            y = p[y][i]
    return p[x][0]
  
if __name__ == "__main__":
    n = int(input())
    #depth
    d = [0] * n
    d[0] = 1
    #parent
    p = [[] for i in range(n)]
    p[0].append(0)
    for i in range(n):
        vi = map(int, input().split()[1:])
        nd = d[i] + 1
        for j in vi:
            p[j].append(i)
            d[j] = nd
    
    #print(p)
    #print(d)
    
    h = int(math.log(max(d),2)) + 1
    for i in range(h - 1):
        for x in range(n):
            p[x].append(p[p[x][i]][i])
    #print(p)
    
    q = int(input())
    for _ in range(q):
        x,y = map(int, input().split())
        print(lca(x,y))

Submission status: Accepted

Solution code:
import sys,queue,math,copy,itertools,bisect,collections,heapq

def main():
    LI = lambda : [int(x) for x in sys.stdin.readline().split()]
    NI = lambda : int(sys.stdin.readline())

    n = NI()
    m = n.bit_length()+1
    root = [[-1] * n for _ in range(m)]
    rev = [0] * n
    depth = [0] * n
    for i in range(n):
        x = LI()
        for a in x[1:]:
            root[0][a] = i
            depth[a] = depth[i] + 1
    for k in range(1,m):
        for i in range(n):
            root[k][i] = root[k-1][root[k-1][i]]

    q = NI()
    for _ in range(q):
        u,v = LI()
        if depth[u] < depth[v] : u,v = v, u
        d = depth[u] - depth[v]
        bit = 1
        for i in range(d.bit_length()):
            if d & bit: u = root[i][u]
            bit <<= 1

        j = depth[u].bit_length() - 1
        while j >= 0:
            if root[j][u] != root[j][v]:
                u = root[j][u]
                v = root[j][v]
            j -= 1
        if u == v:
            print(u)
        else:
            print(root[0][u])

if __name__ == '__main__':
    main()

Submission status: Accepted

Solution code:
import sys,math
sys.setrecursionlimit(1000000)
INF = float("inf")

N = int(sys.stdin.readline())
c = tuple(tuple(map(int,sys.stdin.readline().rstrip().split()))[1:] for _ in range(N)) # multi line with multi param
Q = int(sys.stdin.readline())
uv = tuple(tuple(map(int,sys.stdin.readline().rstrip().split())) for _ in range(Q)) # multi line with multi param
G = [list() for _ in range(N)]

for i,children in enumerate(c):
    G[i] = children

square = [i**2 for i in range(i,40)]
import bisect
#LN = bisect.bisect_left(square,N)+2
LN = math.ceil(math.log2(N))+1
depth = [0]*N
parents = [[0]*N for _ in range(LN)]

def dfs(v,p,l):
    parents[0][v] = p
    depth[v] = l
    for i in G[v]:
        if i != p:
            dfs(i,v,l+1)

dfs(0,-1,0)

for k in range(LN-1):#-1?
    for v in range(N):
        if parents[k][v] < 0:
            parents[k+1][v] = -1
        else:
            parents[k+1][v] = parents[k][parents[k][v]]

def query(u,v):
    if depth[u] > depth[v]:
        u,v = v,u
    while depth[v] != depth[u]:
        v = parents[int(math.log2(depth[v]-depth[u]))][v]
    # for k in range(LN)[::-1]:
    #     if ((depth[v]-depth[u])>>k & 1):
    #         v = parents[k][v]
    assert(depth[u]==depth[v])
    if u == v:
        return u
    for k in range(LN)[::-1]:
        if parents[k][v] != parents[k][u]:
            v = parents[k][v]
            u = parents[k][u]
    return parents[0][u]

ans = []
for u,v in uv:
    print(query(u,v))

Submission status: Accepted

Solution code:
import sys
sys.setrecursionlimit(10**7)

class LCA:
    def __init__(self,N,G,r):
        self.dist=[-1]*N
        self.K=0
        while(2**self.K<N):
            self.K+=1
        self.doubling=[[-1]*N for i in range(self.K+1)]
        self.dfs(G,r,-1,0)
        for k in range(1,self.K+1):
            for i in range(1,N):
                self.doubling[k][i]=self.doubling[k-1][self.doubling[k-1][i]]
        
    def dfs(self,G,v,p,d):
        self.dist[v]=d
        self.doubling[0][v]=p
        for nv in G[v]:
            if nv==p:
                continue
            self.dfs(G,nv,v,d+1)
        
    def get(self,u,v):
        if self.dist[u]<self.dist[v]:
            u,v=v,u
        for k in range(self.K+1):
            if (self.dist[u]-self.dist[v])>>k&1:
                u=self.doubling[k][u]
        if u==v:
            return u
        for k in reversed(range(self.K+1)):
            if self.doubling[k][u]!=self.doubling[k][v]:
                u=self.doubling[k][u]
                v=self.doubling[k][v]
        return self.doubling[0][u]
    
    def getdist(self,u,v):
        return self.dist[u]+self.dist[v]-2*self.dist[self.get(u,v)]

def main():
    N=int(input())
    G=[[] for i in range(N)]
    for i in range(N):
        k=list(map(int,input().split()))
        for j in range(1,len(k)):
            G[i].append(k[j])
            G[k[j]].append(i)
    lca=LCA(N,G,0)
    Q=int(input())
    for i in range(Q):
        a,b=map(int,input().split())
        print(lca.get(a,b))

if __name__=='__main__':
    main()

Submission status: Accepted

Solution code:
from math import log2

class LCA:
    N = 0
    depth = []
    table = []
    
    def init(N, par):
        LCA.N = N
        LCA.depth = [-1] * (N+1)
        max_depth = 0
        
        # set depth
        for i in range(1, N+1):
            if LCA.depth[i] != -1: continue
        
            q = []
            v = i
            
            while True:
                q.append(v)
                if v == par[v]:
                    d = 1
                    break
                if LCA.depth[v] != -1:
                    d = LCA.depth[v]
                    break
                v = par[v]
                
            for v in q[::-1]:
                LCA.depth[v] = d
                d += 1
            max_depth = max(max_depth, d)
                
        t_size = int(log2(max_depth))+1
        LCA.table = [[i for i in range(N+1)] for j in range(t_size)]
        
        for i in range(N+1):
            LCA.table[0][i] = par[i]
        
        for i in range(1, t_size):
            for j in range(1, N+1):
                LCA.table[i][j] = LCA.table[i-1][LCA.table[i-1][j]]
                
    def move(v, m):
        # v の m代の祖先
        i = 0
        while m:
            if m % 2: v = LCA.table[i][v]
            i += 1
            m //= 2
        return v
    
    def same(v, u):
        # v　と uのLCA
        v_d = LCA.depth[v]
        u_d = LCA.depth[u]
        
        if v_d > u_d:
            v, u = u, v
            v_d, u_d = u_d, v_d
            
        diff = u_d - v_d
        
        u = LCA.move(u, diff)
        
        if v == u: return v
        
        l, r = 1, v_d
        
        while l < r:
            mid = (l+r) // 2
            
            v_p = LCA.move(v, mid)
            u_p = LCA.move(u, mid)
            
            if v_p == u_p: r = mid
            else: l = mid+1
        
        return LCA.move(v, l)
    
    def same2(v, u):
        # v の祖先に u がいるか
        if v == u: return True
        
        v_d = LCA.depth[v]
        u_d = LCA.depth[u]
        
        if v_d <= u_d: return False
        
        if LCA.move(v, v_d-u_d) == u: return True
        else: return False

N = int(input())
par = [i for i in range(N+1)]

for i in range(N):
    c = list(map(int, input().split()))

    for j in c[1:]:
        par[j] = i

LCA.init(N, par)

for i in range(int(input())):
    a, b = list(map(int, input().split()))
    print(LCA.same(a, b))

Submission status: Accepted

Solution code:
import sys
input=sys.stdin.readline
class LCA:
  def __init__(self,n,s,edge):
    self.logn=n.bit_length()
    self.parent=[n*[-1]for _ in range(self.logn)]
    self.dist=[0]*n
    stack=[s]
    visited={s}
    for i in stack:
      for j in edge[i]:
        if j in visited:continue
        stack.append(j)
        visited.add(j)
        self.parent[0][j]=i
        self.dist[j]=self.dist[i]+1
        for k in range(1,self.logn):self.parent[k][j]=self.parent[k-1][self.parent[k-1][j]]
  def query(self,a,b):
    if self.dist[a]<self.dist[b]:a,b=b,a
    if self.dist[a]>self.dist[b]:
      for i in range(self.logn):
        if (self.dist[a]-self.dist[b])&(1<<i):a=self.parent[i][a]
    if a==b:return a
    for i in range(self.logn-1,-1,-1):
      if self.parent[i][a]!=self.parent[i][b]:
        a=self.parent[i][a]
        b=self.parent[i][b]
    return self.parent[0][a]
  def path_range(self,a,b):return self.dist[a]+self.dist[b]-2*self.dist[self.query(a,b)]
  def x_in_abpath(self,x,a,b):return self.path_range(a,x)+self.path_range(b,x)==self.path_range(a,b)
n=int(input())
edge=[[]for _ in range(n)]
for i in range(n):
  k=list(map(int,input().split()))
  for j in range(k[0]):edge[i].append(k[j+1])
lca=LCA(n,0,edge)
q=int(input())
for u,v in [list(map(int,input().split()))for _ in range(q)]:
  print(lca.query(u,v))

Submission status: Accepted

Solution code:
import sys
stdin = sys.stdin
inf = 1 << 60
mod = 1000000007
 
ni      = lambda: int(ns())
nin     = lambda y: [ni() for _ in range(y)]
na      = lambda: list(map(int, stdin.readline().split()))
nan     = lambda y: [na() for _ in range(y)]
nf      = lambda: float(ns())
nfn     = lambda y: [nf() for _ in range(y)]
nfa     = lambda: list(map(float, stdin.readline().split()))
nfan    = lambda y: [nfa() for _ in range(y)]
ns      = lambda: stdin.readline().rstrip()
nsn     = lambda y: [ns() for _ in range(y)]
ncl     = lambda y: [list(ns()) for _ in range(y)]
nas     = lambda: stdin.readline().split()

sys.setrecursionlimit(10 ** 7)

class LCA:
    def __init__(self, G, root=0):
        V = len(G)
        K = 1
        while 1 << K < V:
            K += 1
        self.parent = [[-1] * V for _ in range(K)]
        self.dist = [-1] * V
        self.dfs(G, root, -1, 0)
        for k in range(K - 1):
            for v in range(V):
                if self.parent[k][v] < 0:
                    self.parent[k + 1][v] = -1
                else:
                    self.parent[k + 1][v] = self.parent[k][self.parent[k][v]]
    
    def dfs(self, G, v, p, d):
        self.parent[0][v] = p
        self.dist[v] = d
        for nv in G[v]:
            if nv != p:
                self.dfs(G, nv, v, d + 1)
    
    def query(self, u, v):
        if self.dist[u] < self.dist[v]:
            u, v = v, u
        K = len(self.parent)
        for k in range(K):
            if (self.dist[u] - self.dist[v]) >> k & 1:
                u = self.parent[k][u]
        
        if u == v:
            return u
        for k in range(K - 1, -1, -1):
            if self.parent[k][u] != self.parent[k][v]:
                u = self.parent[k][u]
                v = self.parent[k][v]

        return self.parent[0][u]
    
    def get_dist(self, u, v):
        return self.dist[u] + self.dist[v] - 2 * self.dist[self.query(u, v)]
    
    def on_path(self, u, v, a):
        return self.get_dist(u, a) + self.get_dist(a, v) == self.get_dist(u, v)

n = ni()
kc = nan(n)
q = ni()
uv = nan(q)

g = [[] for _ in range(n)]
for i in range(n):
    k = kc[i][0]
    c = kc[i][1:]
    for j in range(k):
        g[i].append(c[j])

lca = LCA(g)
for i in range(q):
    u, v = uv[i]
    print(lca.query(u, v))

Submission status: Accepted

Solution code:
# -*- coding: utf-8 -*-
from functools import lru_cache
import sys
buff_readline = sys.stdin.buffer.readline
readline = sys.stdin.readline

INF = 2**60


def read_int():
    return int(buff_readline())


def read_int_n():
    return list(map(int, buff_readline().split()))


class Doubling():
    def __init__(self, a0):
        """
        a0 is an array-like object which contains ai, 0 <= i < N.
        ai is the next value of i.
        """
        N = len(a0)
        self.N = N
        self.nt = [[None] * N for i in range(N.bit_length()+1)]
        for i, a in enumerate(a0):
            self.nt[0][i] = a

        for i in range(1, len(self.nt)):
            for j in range(N):
                if self.nt[i-1][j] is None:
                    self.nt[i][j] = None
                else:
                    self.nt[i][j] = self.nt[i-1][self.nt[i-1][j]]

    def apply(self, i, n):
        """
        Apply n times from i
        """
        j = i
        for k in range(n.bit_length()):
            m = 1 << k
            if m & n:
                j = self.nt[k][j]
            if j is None:
                break
        return j


class LCA():
    def __init__(self, g, root):
        s = [root]
        self.N = len(g)
        self.p = [None] * self.N
        self.d = [INF] * self.N

        self.p[root] = root
        self.d[root] = 0
        while s:
            u = s.pop()
            for v in g[u]:
                if self.d[v] is INF:
                    self.p[v] = u
                    self.d[v] = self.d[u] + 1
                    s.append(v)

        self.doubling = Doubling(self.p)

    def query(self, u, v):
        if self.d[u] > self.d[v]:
            u, v = v, u
        o = self.d[v] - self.d[u]
        v = self.doubling.apply(v, o)

        if u == v:
            return u

        for k in range(len(self.doubling.nt)-1, -1, -1):
            if self.doubling.nt[k][u] != self.doubling.nt[k][v]:
                u = self.doubling.nt[k][u]
                v = self.doubling.nt[k][v]
        return self.doubling.nt[0][u]


def slv(N, KC, Q, UV):
    g = [list() for _ in range(N)]
    for u, (k, *c) in enumerate(KC):
        for v in c:
            g[u].append(v)
            g[v].append(u)

    lca = LCA(g, 0)

    ans = []
    for u, v in UV:
        i = lca.query(u, v)
        ans.append(i)

    return ans


def main():
    N = read_int()
    KC = [read_int_n() for _ in range(N)]
    Q = read_int()
    UV = [read_int_n() for _ in range(Q)]
    print(*slv(N, KC, Q, UV), sep='\n')


if __name__ == '__main__':
    main()

Submission status: Accepted

Solution code:
import sys
input = sys.stdin.buffer.readline

n = int(input())
li = [list(map(int, input().split()))[1:] for _ in range(n)]


def prepare(n: int, con: list):
	sz = n.bit_length()
	parent = [[0] * n for _ in range(sz)]
	parent[0][0] = -1
	depth = [-1] * n
	depth[0] = 0
	q = [0]
	while q:
		cur = q.pop()
		for nxt in con[cur]:
			if depth[nxt] < 0:
				depth[nxt] = depth[cur] + 1
				parent[0][nxt] = cur
				q.append(nxt)
	for k in range(sz - 1):
		for i in range(n):
			if parent[k][i] < 0:
				parent[k + 1][i] = -1
			else:
				parent[k + 1][i] = parent[k][parent[k][i]]
	return sz, depth, parent


sz, depth, parent = prepare(n, li)


def lca(u, v):
	if depth[u] > depth[v]:
		u, v = v, u
	for k in range(sz):
		if ((depth[v] - depth[u]) >> k & 1):
			v = parent[k][v]
	if u == v:
		return u
	for k in range(sz - 1, -1, -1):
		if parent[k][u] != parent[k][v]:
			u, v = parent[k][u], parent[k][v]
	return parent[0][u]


ans = []
for _ in range(int(input())):
	u, v = map(int, input().split())
	ans.append(lca(u, v))
print("\n".join(map(str, ans)))

Submission status: Accepted

Solution code:
import sys
input = sys.stdin.readline
sys.setrecursionlimit(100000000)
dy = (-1,0,1,0)
dx = (0,1,0,-1)

class LCA():

    def __init__(self,G,root = 0): #O(NlogN)
        self.n = len(G)
        self.G = G
        self.root = root
        self.K = 1 #2 ** K > nとなる最小のK
        while (1<<self.K) <= self.n:
            self.K += 1
        self.parents = [[-1] * self.n for _ in range(self.K)]
        self.dist = [0] * self.n
        
        self._dfs(root,0,-1)
        for k in range(self.K - 1):
            for v in range(self.n):
                if self.parents[k][v] >= 0:
                    self.parents[k + 1][v] = self.parents[k][self.parents[k][v]]
    
    def _dfs(self,i,d,p):
        self.parents[0][i] = p
        self.dist[i] = d
        for e in self.G[i]:
            if e != p:
                self._dfs(e,d + 1,i)
    
    def qry(self,u,v): #O(logN)
        if self.dist[u] < self.dist[v]:
            u,v = v,u
        
        dif = self.dist[u] - self.dist[v]
        for k in range(self.K):
            if dif >> k & 1:
                u = self.parents[k][u]
        
        if u == v:
            return u
        
        for k in range(self.K - 1,-1,-1):
            if self.parents[k][u] != self.parents[k][v]:
                u = self.parents[k][u]
                v = self.parents[k][v]
        
        return self.parents[0][u]

def main():
    n = int(input())
    G = [[] for _ in range(n)]
    for i in range(n):
        a = list(map(int,input().split()))
        k = a[0]
        for e in a[1:]:
            G[e].append(i)
            G[i].append(e)

    lca = LCA(G)
    q = int(input())
    for _ in range(q):
        u,v = map(int,input().split())
        print(lca.qry(u,v))

if __name__ == '__main__':
    main()