Problem:


Score : 600 points

Problem Statement

We have a tree with N vertices numbered 1 to N.
The i-th edge in this tree connects Vertex a_i and Vertex b_i.

Consider painting each of these edges white or black. There are 2^{N-1} such ways to paint the edges. Among them, how many satisfy all of the following M restrictions?  

The i-th (1 \leq i \leq M) restriction is represented by two integers u_i and v_i, which mean that the path connecting Vertex u_i and Vertex v_i must contain at least one edge painted black.

Constraints

2 \leq N \leq 50

1 \leq a_i,b_i \leq N

The graph given in input is a tree.

1 \leq M \leq \min(20,\frac{N(N-1)}{2})

1 \leq u_i < v_i \leq N

If i \not= j, either u_i \not=u_j or v_i\not=v_j

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N
a_1 b_1
:
a_{N-1} b_{N-1}
M
u_1 v_1
:
u_M v_M

Output

Print the number of ways to paint the edges that satisfy all of the M conditions.

Sample Input 1

3
1 2
2 3
1
1 3

Sample Output 1

3

The tree in this input is shown below:

All of the M restrictions will be satisfied if Edge 1 and 2 are respectively painted (white, black), (black, white), or (black, black), so the answer is 3.

Sample Input 2

2
1 2
1
1 2

Sample Output 2

1

The tree in this input is shown below:

All of the M restrictions will be satisfied only if Edge 1 is painted black, so the answer is 1.

Sample Input 3

5
1 2
3 2
3 4
5 3
3
1 3
2 4
2 5

Sample Output 3

9

The tree in this input is shown below:

Sample Input 4

8
1 2
2 3
4 3
2 5
6 3
6 7
8 6
5
2 7
3 5
1 6
2 8
7 8

Sample Output 4

62

The tree in this input is shown below:



Sample input:
3
1 2
2 3
1
1 3


Sample output:
3

Submission status: Wrong Answer

Solution code:
#!/usr/bin/env python3
import sys
sys.setrecursionlimit(10**8)
input = sys.stdin.readline
 
n = int(input())
edge = [[] for _ in range(n)]
edge_dict = dict()
edges = []
 
for i in range(n - 1):
    a, b = [int(item) - 1 for item in input().split()]
    edge[a].append(b)
    edge[b].append(a)
    if a > b:
        edge_dict[(b, a)] = i
        edges.append((b, a))
    else:
        edge_dict[(a, b)] = i
        edges.append((a, b))
 
m = int(input())
uv = []
for _ in range(m):
    uv.append([int(item) - 1 for item in input().split()])
 
def dfs(p, v, dest):
    if v == dest:
        return [v]
    if p != -1 and len(edge[v]) == 1:
        return False
    for nv in edge[v]:
        if nv == p:
            continue
        ret = dfs(v, nv, dest)
        if ret:
            return ret + [v]
 
state = [set() for _ in range(m)]
for i, (u, v) in enumerate(uv):
    ret = dfs(-1, u, v)
    for uu, vv in zip(ret, ret[1:]):
        if uu > vv:
            uu, vv = vv, uu
        if (uu, vv) in edge_dict:
            state[i].add(edge_dict[(uu, vv)])
 
# DP[i-th item][fills uv as st]
dp = [[0] * 2**m for _ in range(n - 1)]
dp[0][0] = 1
a, b = edges[0]
status = 0
for i, st in enumerate(state):
    if 0 in st:
        status |= 1 << i
dp[0][status] = 1
 
for i, (a, b) in enumerate(edges):
    if i == 0:
        continue
    status = 0
    for j, st in enumerate(state):
        if i in st:
            status |= 1 << j
    for k in range(2**m):
        # Fill black
        dp[i][k | status] += dp[i-1][k]
        # Fill white
        dp[i][k] += dp[i-1][k]
 
print(dp[-1][-1])

Submission status: Wrong Answer

Solution code:
n=int(input())
g=[[] for i in range(n)]
tr=[set([]) for i in range(n-1)]
l=[]
for i in range(n-1):
    a,b=map(int,input().split())
    l.append([a-1,b-1])
    g[a-1].append(b-1)
    g[b-1].append(a-1)
m=int(input())
p=[]
for i in range(m):
    c,d=map(int,input().split())
    p.append([c-1,d-1])
for i in range(m):
    q=[[p[i][0]]]
    goal=p[i][1]
    v=[0]*n
    v[p[i][0]]=1
    df=0
    while True:
        qq=q.pop(0)
        go=qq[-1]
        for j in g[go]:
            if j==goal:
                sg=qq+[j]
                df=1
                break      
            if v[j]==0:
                q.append(qq+[j])
                v[j]=1
        if df==1:
            break
    for ii in range(len(sg)-1):
        for j in range(n-1):
            if l[j]==[sg[ii],sg[ii+1]] or l[j]==[sg[ii+1],sg[ii]]:
                tr[j].add(i)
                break

Submission status: Wrong Answer

Solution code:
#!/usr/bin/env python3
import sys
sys.setrecursionlimit(10**8)
input = sys.stdin.readline

n = int(input())
edge = [[] for _ in range(n)]
edge_dict = dict()
edges = []

for i in range(n - 1):
    a, b = [int(item) - 1 for item in input().split()]
    edge[a].append(b)
    edge[b].append(a)
    if a > b:
        edge_dict[(b, a)] = i
        edges.append((b, a))
    else:
        edge_dict[(a, b)] = i
        edges.append((a, b))

m = int(input())
uv = []
for _ in range(m):
    uv.append([int(item) - 1 for item in input().split()])

def dfs(p, v, dest):
    if v == dest:
        return [v]
    if p != -1 and len(edge[v]) == 1:
        return False
    for nv in edge[v]:
        if nv == p:
            continue
        ret = dfs(v, nv, dest)
        if ret:
            return ret + [v]

state = [set() for _ in range(m)]
for i, (u, v) in enumerate(uv):
    ret = dfs(-1, u, v)
    for uu, vv in zip(ret, ret[1:]):
        if uu > vv:
            uu, vv = vv, uu
        if (uu, vv) in edge_dict:
            state[i].add(edge_dict[(uu, vv)])

# DP[i-th item][fills uv as st]
dp = [[0] * 2**m for _ in range(n - 1)]
dp[0][0] = 1
a, b = edges[0]
status = 0
for i, st in enumerate(state):
    if 0 in st:
        status |= 1 << i
dp[0][status] = 1

seen_state = set()
seen_state.add(0)
seen_state.add(status)
for i, (a, b) in enumerate(edges):
    if i == 0:
        continue
    status = 0
    for j, st in enumerate(state):
        if i in st:
            status |= 1 << j
    to_add = set()
    for k in seen_state:
        # Fill black
        dp[i][k | status] += dp[i-1][k]
        to_add.add(k | status)
        # Fill white
        dp[i][k] += dp[i-1][k]
    seen_state.update(to_add)

print(dp[-1][-1])

Submission status: Time Limit Exceeded

Solution code:
from copy import deepcopy
from itertools import product

class EulerTour:
    def __init__(self, N):
        self.N = N
        self.G = [[] for _ in range(N)]
    
    def add_edge(self, a, b):
        self.G[a].append(b)
        self.G[b].append(a)
    
    def from_graph(self, G, copy=False):
        if copy: self.G = deepcopy(G)
        else: self.G = G
            
    def build(self, root=0, lca=True):
        self.root = root
        self._dfs(root)
        self.In = [0]*self.N
        self.Out = [0]*self.N
        for i, v in enumerate(self.node_list):
            if self.In[v] == 0:
                self.In[v] = i
            self.Out[v] = i
        if lca:
            self.seg = SegTree(len(self.node_list))
            self.seg.build([self.d[self.node_list[i]] for i in range(len(self.node_list))])
    
    def lca(self, a, b):
        if self.root in (a,b):
            return self.root
        a_out, b_in = self.Out[a], self.In[b]
        if a_out > b_in:
            a_out, b_in = self.Out[b], self.In[a]
        if a_out > b_in:
            a_out, b_in = self.Out[b], self.Out[a]
        if a_out > b_in:
            a_out, b_in = self.Out[a], self.Out[b]
        idx = self.seg.find(a_out, b_in+1)
        return self.node_list[idx]
            
    def _dfs(self, root=0):
        self.idx2edge = {}
        self.edge2idx = {}
        self.node_list = []
        self.edge_list = []
        seen = [0]*len(self.G)
        prev = [0]*len(self.G)
        self.d =[-1]*len(self.G)
        todo = [~root, root]
        count = 0
        while todo:
            a = todo.pop()
            if a >= 0:
                seen[a] = 1
                self.d[a] = self.d[prev[a]] + 1
                edge = (prev[a], a)
                self.idx2edge[count] = edge
                self.edge2idx[edge] = count
                self.edge_list.append(count)
                self.node_list.append(a)
                count += 1
                for b in reversed(self.G[a]):
                    if seen[b]: continue
                    todo.append(~b)
                    todo.append(b)
                    prev[b] = a
            else: 
                edge = (prev[~a], ~a)
                idx = self.edge2idx[edge]
                self.edge_list.append(-idx)
                if ~a != root: self.node_list.append(prev[~a])
                    
class SegTree:
    """ segment tree with point modification and range product. """
    # # https://yukicoder.me/submissions/452850
    def __init__(self, N, data_f = min, data_unit=1<<30):
        self.N = N
        self.data_f = data_f
        self.data_unit = data_unit
        self.data = [self.data_unit] * (N + N)

    def build(self, raw_data):
        data = self.data
        f = self.data_f
        N = self.N
        data[N:] = raw_data[:]
        for i in range(N - 1, 0, -1):
            data[i] = f(data[i << 1], data[i << 1 | 1])

    def set_val(self, i, x):
        data = self.data
        f = self.data_f
        i += self.N
        data[i] = x
        while i > 1:
            data[i >> 1] = f(data[i], data[i ^ 1])
            i >>= 1

    def fold(self, L, R):
        """ compute for [L, R) """
        vL = vR = self.data_unit
        data = self.data
        f = self.data_f
        L += self.N
        R += self.N
        while L < R:
            if L & 1:
                vL = f(vL, data[L])
                L += 1
            if R & 1:
                R -= 1
                vR = f(data[R], vR)
            L >>= 1
            R >>= 1
        return f(vL, vR)
    
    def find(self, L, R):
        x = self.fold(L,R)
        while R-L>1:
            M = (R+L)//2
            if self.fold(L,M)==x: R = M
            else: L = M
        return L

from collections import deque

def bfs(G,s,edge2idx):
    seen = [0]*N
    todo = deque()
    seen[s]=1
    todo.append(s)
    cumedge = [set() for _ in range(N)]
    while len(todo):
      a = todo.popleft()
      for b in G[a]:
        if seen[b] == 0:
          seen[b] = 1
          todo.append(b)
          cumedge[b] = deepcopy(cumedge[a])
          idx = edge2idx[(a,b)]
          cumedge[b].add(idx)
    return cumedge
      
N=int(input())
et = EulerTour(N)
for i in range(N-1):
  a,b=map(int,input().split())
  et.add_edge(a-1,b-1)
  
et.build(0)
cumedge = bfs(et.G,0,et.edge2idx)

M = int(input())
path_list = [0]*M
for i in range(M):
  u,v = map(int,input().split())
  u,v = u-1,v-1
  w = et.lca(u,v)
  path_list[i] = (cumedge[u] - cumedge[w]) | (cumedge[v] - cumedge[w])

ans = 2**(N-1)
for i,p in enumerate(product(range(2),repeat=M)):
  if i == 0: continue
  union = set.union(*[path_list[i] for i in range(M) if p[i]])
  ans += (-1)**sum(p) * 2**(N-1-len(union))

print(ans)

Submission status: Time Limit Exceeded

Solution code:
import sys
sys.setrecursionlimit(10**7)
def main(n,ki,uv):
  # n: 頂点数
  # ki: 木
  # Euler Tour の構築
  S=[] # Euler Tour
  F=[0]*n # F[v]:vにはじめて訪れるステップ
  depth=[0]*n # 0を根としたときの深さ
  def dfs(v,pare,d):
      F[v]=len(S)
      depth[v]=d
      S.append(v)
      for i,w in ki[v]:
          if w==pare:continue
          dfs(w,v,d+1)
          S.append(v)
  dfs(0,-1,0)
  # Sをセグメント木に乗せる
  # u,vのLCAを求める:S[F[u]:F[v]+1]のなかでdepthが最小の頂点を探せば良い
  # F[u]:uに初めてたどるつくステップ
  # S[F[u]:F[v]+1]:はじめてuにたどり着いてつぎにvにたどるつくまでに訪れる頂点
  # 存在しない範囲は深さが他よりも大きくなるようにする
  INF = (n, None)
  # LCAを計算するクエリの前計算
  M = 2*n
  M0 = 2**(M-1).bit_length() # M以上で最小の2のべき乗
  data = [INF]*(2*M0)
  for i, v in enumerate(S):
    data[M0-1+i] = (depth[v], i)
  for i in range(M0-2, -1, -1):
    data[i] = min(data[2*i+1], data[2*i+2])
  # LCAの計算 (generatorで最小値を求める)
  def _query(a, b):
    yield INF
    a += M0; b += M0
    while a < b:
      if b & 1:
        b -= 1
        yield data[b-1]
      if a & 1:
        yield data[a-1]
        a += 1
      a >>= 1; b >>= 1
  # LCAの計算 (外から呼び出す関数)
  def query(u, v):
    fu = F[u]; fv = F[v]
    if fu > fv:
      fu, fv = fv, fu
    return S[min(_query(fu, fv+1))[1]]
  

  todo=[[0,[]]]
  path=[[]]*n
  mi=[1]*n
  while todo:
    v,ary=todo.pop()
    path[v]=ary
    mi[v]=0
    for i,nv in ki[v]:
      if mi[nv]==1:
        todo.append([nv,ary+[i]])
        mi[nv]=1
  #print(path)
  for i in range(n):
    path[i]=set(path[i])
  memo={}
  ans=0
  for i in range(2**m):
    chk=set(())
    for j in range(m):
      if (i>>j)&1:
        chk.add(j)
    must_w=set(())
    for c in chk:
      u,v=uv[c]
      if c in memo:
        tmp=memo[(u,v)]
      else:
        dd=query(u,v)
        tmp=path[u]|path[v]
        tmp-=path[dd]
        memo[(u,v)]=tmp
      must_w|=tmp
    t=n-1-len(must_w)
    if len(chk)%2==1:
      ans-=pow(2,t)
    else:
      ans+=pow(2,t)
  print(ans)
if __name__=='__main__':
  n=int(input())
  ki=[[] for _ in range(n)]
  for i in range(n-1):
    u,v=map(int,input().split())
    u,v=u-1,v-1
    ki[u].append([i,v])
    ki[v].append([i,u])
  m=int(input())
  uv=[]
  for _ in range(m):
    u,v=map(int,input().split())
    u,v=u-1,v-1
    uv.append([u,v])
  main(n,ki,uv)

Submission status: Time Limit Exceeded

Solution code:
import sys
sys.setrecursionlimit(10**7)
def main(n,ki,uv):
  # n: 頂点数
  # ki: 木
  # Euler Tour の構築
  S=[] # Euler Tour
  F=[0]*n # F[v]:vにはじめて訪れるステップ
  depth=[0]*n # 0を根としたときの深さ
  def dfs(v,pare,d):
    F[v]=len(S)
    depth[v]=d
    S.append(v)
    for i,w in ki[v]:
      if w==pare:continue
      dfs(w,v,d+1)
      S.append(v)
  dfs(0,-1,0)
  # Sをセグメント木に乗せる
  # u,vのLCAを求める:S[F[u]:F[v]+1]のなかでdepthが最小の頂点を探せば良い
  # F[u]:uに初めてたどるつくステップ
  # S[F[u]:F[v]+1]:はじめてuにたどり着いてつぎにvにたどるつくまでに訪れる頂点
  # 存在しない範囲は深さが他よりも大きくなるようにする
  INF = (n, None)
  # LCAを計算するクエリの前計算
  M = 2*n
  M0 = 2**(M-1).bit_length() # M以上で最小の2のべき乗
  data = [INF]*(2*M0)
  for i, v in enumerate(S):
    data[M0-1+i] = (depth[v], i)
  for i in range(M0-2, -1, -1):
    data[i] = min(data[2*i+1], data[2*i+2])
  # LCAの計算 (generatorで最小値を求める)
  def _query(a, b):
    yield INF
    a += M0; b += M0
    while a < b:
      if b & 1:
        b -= 1
        yield data[b-1]
      if a & 1:
        yield data[a-1]
        a += 1
      a >>= 1; b >>= 1
  # LCAの計算 (外から呼び出す関数)
  def query(u, v):
    fu = F[u]; fv = F[v]
    if fu > fv:
      fu, fv = fv, fu
    return S[min(_query(fu, fv+1))[1]]
  
  todo=[[0,[]]]
  path=[[]]*n
  mi=[1]*n
  while todo:
    v,ary=todo.pop()
    path[v]=ary
    mi[v]=0
    for i,nv in ki[v]:
      if mi[nv]==1:
        todo.append([nv,ary+[i]])
        mi[nv]=1

  for i in range(n):
    path[i]=set(path[i])
  memo=[set(())]*m
  for c in range(m):
    u,v=uv[c]
    dd=query(u,v)
    tmp=path[u]|path[v]
    tmp-=path[dd]
    memo[c]=tmp

  ans=0
  for i in range(2**m):
    chk=set(())
    for j in range(m):
      if (i>>j)&1:
        chk.add(j)
    must_w=set(())
    for c in chk:
      tmp=memo[c]
      must_w|=tmp
    t=n-1-len(must_w)
    if len(chk)%2==1:
      ans-=pow(2,t)
    else:
      ans+=pow(2,t)
  print(ans)
if __name__=='__main__':
  n=int(input())
  ki=[[] for _ in range(n)]
  for i in range(n-1):
    u,v=map(int,input().split())
    u,v=u-1,v-1
    ki[u].append([i,v])
    ki[v].append([i,u])
  m=int(input())
  uv=[]
  for _ in range(m):
    u,v=map(int,input().split())
    u,v=u-1,v-1
    uv.append([u,v])
  main(n,ki,uv)

Submission status: Time Limit Exceeded

Solution code:
import sys
sys.setrecursionlimit(10**7)
def main(n,ki,uv):
  # n: 頂点数
  # ki: 木
  # Euler Tour の構築
  S=[] # Euler Tour
  F=[0]*n # F[v]:vにはじめて訪れるステップ
  depth=[0]*n # 0を根としたときの深さ
  def dfs(v,pare,d):
      F[v]=len(S)
      depth[v]=d
      S.append(v)
      for i,w in ki[v]:
          if w==pare:continue
          dfs(w,v,d+1)
          S.append(v)
  dfs(0,-1,0)
  # Sをセグメント木に乗せる
  # u,vのLCAを求める:S[F[u]:F[v]+1]のなかでdepthが最小の頂点を探せば良い
  # F[u]:uに初めてたどるつくステップ
  # S[F[u]:F[v]+1]:はじめてuにたどり着いてつぎにvにたどるつくまでに訪れる頂点
  # 存在しない範囲は深さが他よりも大きくなるようにする
  INF = (n, None)
  # LCAを計算するクエリの前計算
  M = 2*n
  M0 = 2**(M-1).bit_length() # M以上で最小の2のべき乗
  data = [INF]*(2*M0)
  for i, v in enumerate(S):
    data[M0-1+i] = (depth[v], i)
  for i in range(M0-2, -1, -1):
    data[i] = min(data[2*i+1], data[2*i+2])
  # LCAの計算 (generatorで最小値を求める)
  def _query(a, b):
    yield INF
    a += M0; b += M0
    while a < b:
      if b & 1:
        b -= 1
        yield data[b-1]
      if a & 1:
        yield data[a-1]
        a += 1
      a >>= 1; b >>= 1
  # LCAの計算 (外から呼び出す関数)
  def query(u, v):
    fu = F[u]; fv = F[v]
    if fu > fv:
      fu, fv = fv, fu
    return S[min(_query(fu, fv+1))[1]]
  

  todo=[[0,[]]]
  path=[[]]*n
  mi=[1]*n
  while todo:
    v,ary=todo.pop()
    path[v]=ary
    mi[v]=0
    for i,nv in ki[v]:
      if mi[nv]==1:
        todo.append([nv,ary+[i]])
        mi[nv]=1
  #print(path)
  for i in range(n):
    path[i]=set(path[i])
  memo={}
  ans=0
  for i in range(2**m):
    chk=set(())
    for j in range(m):
      if (i>>j)&1:
        chk.add(j)
    must_w=set(())
    for c in chk:
      u,v=uv[c]
      if c in memo:
        tmp=memo[(u,v)]
      else:
        dd=query(u,v)
        tmp=path[u].union(path[v])
        tmp=tmp-path[dd]
        memo[(u,v)]=tmp
      must_w=must_w.union(tmp)
    t=n-1-len(must_w)
    if len(chk)%2==1:
      ans-=pow(2,t)
    else:
      ans+=pow(2,t)
  print(ans)
if __name__=='__main__':
  n=int(input())
  ki=[[] for _ in range(n)]
  for i in range(n-1):
    u,v=map(int,input().split())
    u,v=u-1,v-1
    ki[u].append([i,v])
    ki[v].append([i,u])
  m=int(input())
  uv=[]
  for _ in range(m):
    u,v=map(int,input().split())
    u,v=u-1,v-1
    uv.append([u,v])
  main(n,ki,uv)

Submission status: Time Limit Exceeded

Solution code:
import sys
sys.setrecursionlimit(10**7)
def main(n,ki,uv):
  # n: 頂点数
  # ki: 木
  # Euler Tour の構築
  S=[] # Euler Tour
  F=[0]*n # F[v]:vにはじめて訪れるステップ
  depth=[0]*n # 0を根としたときの深さ
  def dfs(v,pare,d):
      F[v]=len(S)
      depth[v]=d
      S.append(v)
      for i,w in ki[v]:
          if w==pare:continue
          dfs(w,v,d+1)
          S.append(v)
  dfs(0,-1,0)
  # Sをセグメント木に乗せる
  # u,vのLCAを求める:S[F[u]:F[v]+1]のなかでdepthが最小の頂点を探せば良い
  # F[u]:uに初めてたどるつくステップ
  # S[F[u]:F[v]+1]:はじめてuにたどり着いてつぎにvにたどるつくまでに訪れる頂点
  # 存在しない範囲は深さが他よりも大きくなるようにする
  INF = (n, None)
  # LCAを計算するクエリの前計算
  M = 2*n
  M0 = 2**(M-1).bit_length() # M以上で最小の2のべき乗
  data = [INF]*(2*M0)
  for i, v in enumerate(S):
    data[M0-1+i] = (depth[v], i)
  for i in range(M0-2, -1, -1):
    data[i] = min(data[2*i+1], data[2*i+2])
  # LCAの計算 (generatorで最小値を求める)
  def _query(a, b):
    yield INF
    a += M0; b += M0
    while a < b:
      if b & 1:
        b -= 1
        yield data[b-1]
      if a & 1:
        yield data[a-1]
        a += 1
      a >>= 1; b >>= 1
  # LCAの計算 (外から呼び出す関数)
  def query(u, v):
    fu = F[u]; fv = F[v]
    if fu > fv:
      fu, fv = fv, fu
    return S[min(_query(fu, fv+1))[1]]
  

  todo=[[0,[]]]
  path=[[]]*n
  mi=[1]*n
  while todo:
    v,ary=todo.pop()
    path[v]=ary
    mi[v]=0
    for i,nv in ki[v]:
      if mi[nv]==1:
        todo.append([nv,ary+[i]])
        mi[nv]=1
  #print(path)
  for i in range(n):
    path[i]=set(path[i])
  memo={}
  ans=0
  for i in range(2**m):
    chk=set(())
    for j in range(m):
      if (i>>j)&1:
        chk.add(j)
    must_w=set(())
    for c in chk:
      if c in memo:
        tmp=memo[c]
      else:
        u,v=uv[c]
        dd=query(u,v)
        tmp=path[u]|path[v]
        tmp=tmp-path[dd]
        memo[(u,v)]=tmp
      must_w|=tmp
    t=n-1-len(must_w)
    if len(chk)%2==1:
      ans-=pow(2,t)
    else:
      ans+=pow(2,t)
  print(ans)
if __name__=='__main__':
  n=int(input())
  ki=[[] for _ in range(n)]
  for i in range(n-1):
    u,v=map(int,input().split())
    u,v=u-1,v-1
    ki[u].append([i,v])
    ki[v].append([i,u])
  m=int(input())
  uv=[]
  for _ in range(m):
    u,v=map(int,input().split())
    u,v=u-1,v-1
    uv.append([u,v])
  main(n,ki,uv)

Submission status: Time Limit Exceeded

Solution code:
import sys
sys.setrecursionlimit(10**7)
def main(n,ki,uv):
  # n: 頂点数
  # ki: 木
  # Euler Tour の構築
  S=[] # Euler Tour
  F=[0]*n # F[v]:vにはじめて訪れるステップ
  depth=[0]*n # 0を根としたときの深さ
  def dfs(v,pare,d):
      F[v]=len(S)
      depth[v]=d
      S.append(v)
      for i,w in ki[v]:
          if w==pare:continue
          dfs(w,v,d+1)
          S.append(v)
  dfs(0,-1,0)
  # Sをセグメント木に乗せる
  # u,vのLCAを求める:S[F[u]:F[v]+1]のなかでdepthが最小の頂点を探せば良い
  # F[u]:uに初めてたどるつくステップ
  # S[F[u]:F[v]+1]:はじめてuにたどり着いてつぎにvにたどるつくまでに訪れる頂点
  # 存在しない範囲は深さが他よりも大きくなるようにする
  INF = (n, None)
  # LCAを計算するクエリの前計算
  M = 2*n
  M0 = 2**(M-1).bit_length() # M以上で最小の2のべき乗
  data = [INF]*(2*M0)
  for i, v in enumerate(S):
    data[M0-1+i] = (depth[v], i)
  for i in range(M0-2, -1, -1):
    data[i] = min(data[2*i+1], data[2*i+2])
  # LCAの計算 (generatorで最小値を求める)
  def _query(a, b):
    yield INF
    a += M0; b += M0
    while a < b:
      if b & 1:
        b -= 1
        yield data[b-1]
      if a & 1:
        yield data[a-1]
        a += 1
      a >>= 1; b >>= 1
  # LCAの計算 (外から呼び出す関数)
  def query(u, v):
    fu = F[u]; fv = F[v]
    if fu > fv:
      fu, fv = fv, fu
    return S[min(_query(fu, fv+1))[1]]
  

  todo=[[0,[]]]
  path=[[]]*n
  mi=[1]*n
  while todo:
    v,ary=todo.pop()
    path[v]=ary
    mi[v]=0
    for i,nv in ki[v]:
      if mi[nv]==1:
        todo.append([nv,ary+[i]])
        mi[nv]=1
  #print(path)
  for i in range(n):
    path[i]=set(path[i])
  memo={}
  ans=0
  for i in range(2**m):
    chk=set(())
    for j in range(m):
      if (i>>j)&1:
        chk.add(j)
    must_w=set(())
    for c in chk:
      if c in memo:
        tmp=memo[c]
      else:
        u,v=uv[c]
        dd=query(u,v)
        tmp=path[u].union(path[v])
        tmp=tmp-path[dd]
        memo[(u,v)]=tmp
      must_w=must_w.union(tmp)
    t=n-1-len(must_w)
    if len(chk)%2==1:
      ans-=pow(2,t)
    else:
      ans+=pow(2,t)
  print(ans)
if __name__=='__main__':
  n=int(input())
  ki=[[] for _ in range(n)]
  for i in range(n-1):
    u,v=map(int,input().split())
    u,v=u-1,v-1
    ki[u].append([i,v])
    ki[v].append([i,u])
  m=int(input())
  uv=[]
  for _ in range(m):
    u,v=map(int,input().split())
    u,v=u-1,v-1
    uv.append([u,v])
  main(n,ki,uv)

Submission status: Time Limit Exceeded

Solution code:
import sys
sys.setrecursionlimit(10**7)
def main(n,ki,uv):
  # n: 頂点数
  # ki: 木
  # Euler Tour の構築
  S=[] # Euler Tour
  F=[0]*n # F[v]:vにはじめて訪れるステップ
  depth=[0]*n # 0を根としたときの深さ
  def dfs(v,pare,d):
    F[v]=len(S)
    depth[v]=d
    S.append(v)
    for i,w in ki[v]:
      if w==pare:continue
      dfs(w,v,d+1)
      S.append(v)
  dfs(0,-1,0)
  # Sをセグメント木に乗せる
  # u,vのLCAを求める:S[F[u]:F[v]+1]のなかでdepthが最小の頂点を探せば良い
  # F[u]:uに初めてたどるつくステップ
  # S[F[u]:F[v]+1]:はじめてuにたどり着いてつぎにvにたどるつくまでに訪れる頂点
  # 存在しない範囲は深さが他よりも大きくなるようにする
  INF = (n, None)
  # LCAを計算するクエリの前計算
  M = 2*n
  M0 = 2**(M-1).bit_length() # M以上で最小の2のべき乗
  data = [INF]*(2*M0)
  for i, v in enumerate(S):
    data[M0-1+i] = (depth[v], i)
  for i in range(M0-2, -1, -1):
    data[i] = min(data[2*i+1], data[2*i+2])
  # LCAの計算 (generatorで最小値を求める)
  def _query(a, b):
    yield INF
    a += M0; b += M0
    while a < b:
      if b & 1:
        b -= 1
        yield data[b-1]
      if a & 1:
        yield data[a-1]
        a += 1
      a >>= 1; b >>= 1
  # LCAの計算 (外から呼び出す関数)
  def query(u, v):
    fu = F[u]; fv = F[v]
    if fu > fv:
      fu, fv = fv, fu
    return S[min(_query(fu, fv+1))[1]]
  
  memo={}

  todo=[[0,[]]]
  path=[[]]*n
  mi=[1]*n
  while todo:
    v,ary=todo.pop()
    path[v]=ary
    mi[v]=0
    for i,nv in ki[v]:
      if mi[nv]==1:
        todo.append([nv,ary+[i]])
        mi[nv]=1
  #print(path)
  for i in range(n):
    path[i]=set(path[i])
  ans=2**(n-1)
  for i in range(2**m):
    chk=set(())
    for j in range(m):
      if (i>>j)&1:
        chk.add(j)
    if not chk:continue
    must_w=set(())
    for c in chk:
      u,v=uv[c]
      if (u,v) in memo:
        tmp=memo[(u,v)]
      else:
        dd=query(u,v)
        tmp=path[u].union(path[v])
        tmp=tmp-path[dd]
        memo[(u,v)]=tmp
      must_w=must_w.union(tmp)
    t=n-1-len(must_w)
    if len(chk)%2==1:
      ans-=pow(2,t)
    else:
      ans+=pow(2,t)
  print(ans)
if __name__=='__main__':
  n=int(input())
  ki=[[] for _ in range(n)]
  for i in range(n-1):
    u,v=map(int,input().split())
    u,v=u-1,v-1
    ki[u].append([i,v])
    ki[v].append([i,u])
  m=int(input())
  uv=[]
  for _ in range(m):
    u,v=map(int,input().split())
    u,v=u-1,v-1
    uv.append([u,v])
  main(n,ki,uv)

Submission status: Time Limit Exceeded

Solution code:
import sys
sys.setrecursionlimit(10**7)
def main(n,ki,uv):
  # n: 頂点数
  # ki: 木
  # Euler Tour の構築
  S=[] # Euler Tour
  F=[0]*n # F[v]:vにはじめて訪れるステップ
  depth=[0]*n # 0を根としたときの深さ
  def dfs(v,pare,d):
      F[v]=len(S)
      depth[v]=d
      S.append(v)
      for i,w in ki[v]:
          if w==pare:continue
          dfs(w,v,d+1)
          S.append(v)
  dfs(0,-1,0)
  # Sをセグメント木に乗せる
  # u,vのLCAを求める:S[F[u]:F[v]+1]のなかでdepthが最小の頂点を探せば良い
  # F[u]:uに初めてたどるつくステップ
  # S[F[u]:F[v]+1]:はじめてuにたどり着いてつぎにvにたどるつくまでに訪れる頂点
  # 存在しない範囲は深さが他よりも大きくなるようにする
  INF = (n, None)
  # LCAを計算するクエリの前計算
  M = 2*n
  M0 = 2**(M-1).bit_length() # M以上で最小の2のべき乗
  data = [INF]*(2*M0)
  for i, v in enumerate(S):
    data[M0-1+i] = (depth[v], i)
  for i in range(M0-2, -1, -1):
    data[i] = min(data[2*i+1], data[2*i+2])
  # LCAの計算 (generatorで最小値を求める)
  def _query(a, b):
    yield INF
    a += M0; b += M0
    while a < b:
      if b & 1:
        b -= 1
        yield data[b-1]
      if a & 1:
        yield data[a-1]
        a += 1
      a >>= 1; b >>= 1
  # LCAの計算 (外から呼び出す関数)
  def query(u, v):
    fu = F[u]; fv = F[v]
    if fu > fv:
      fu, fv = fv, fu
    return S[min(_query(fu, fv+1))[1]]
  
  memo={}

  todo=[[0,[]]]
  path=[[]]*n
  mi=[1]*n
  while todo:
    v,ary=todo.pop()
    path[v]=ary
    mi[v]=0
    for i,nv in ki[v]:
      if mi[nv]==1:
        todo.append([nv,ary+[i]])
        mi[nv]=1
  #print(path)
  for i in range(n):
    path[i]=set(path[i])
  ans=2**(n-1)
  for i in range(2**m):
    chk=set(())
    for j in range(m):
      if (i>>j)&1:
        chk.add(j)
    if not chk:continue
    must_w=set(())
    for c in chk:
      u,v=uv[c]
      if (u,v) in memo:
        tmp=memo[(u,v)]
      else:
        dd=query(u,v)
        tmp=path[u].union(path[v])
        tmp=tmp-path[dd]
        memo[(u,v)]=tmp
      must_w=must_w.union(tmp)
    t=n-1-len(must_w)
    if len(chk)%2==1:
      ans-=pow(2,t)
    else:
      ans+=pow(2,t)
  print(ans)
if __name__=='__main__':
  n=int(input())
  ki=[[] for _ in range(n)]
  for i in range(n-1):
    u,v=map(int,input().split())
    u,v=u-1,v-1
    ki[u].append([i,v])
    ki[v].append([i,u])
  m=int(input())
  uv=[]
  for _ in range(m):
    u,v=map(int,input().split())
    u,v=u-1,v-1
    uv.append([u,v])
  main(n,ki,uv)

Submission status: Time Limit Exceeded

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

n=int(input())
kk=[[] for _ in range(n)]
ki=[[] for _ in range(n)]
for i in range(n-1):
  u,v=map(int,input().split())
  u,v=u-1,v-1
  ki[u].append([i,v])
  ki[v].append([i,u])
m=int(input())
uv=[]
for _ in range(m):
  u,v=map(int,input().split())
  u,v=u-1,v-1
  uv.append([u,v])

# n: 頂点数
# ki[v]: 頂点vの子頂点 (親頂点は含まない)
# Euler Tour の構築
S=[]
F=[0]*n
depth=[0]*n
def dfs(v,pare,d):
    F[v]=len(S)
    depth[v]=d
    S.append(v)
    for i,w in ki[v]:
        if w==pare:continue
        dfs(w,v,d+1)
        S.append(v)
dfs(0,-1,0)
#print(S)
# 存在しない範囲は深さが他よりも大きくなるようにする
INF = (n, None)

# LCAを計算するクエリの前計算
M = 2*n
M0 = 2**(M-1).bit_length()
data = [INF]*(2*M0)
for i, v in enumerate(S):
    data[M0-1+i] = (depth[v], i)
for i in range(M0-2, -1, -1):
    data[i] = min(data[2*i+1], data[2*i+2])

# LCAの計算 (generatorで最小値を求める)
def _query(a, b):
    yield INF
    a += M0; b += M0
    while a < b:
        if b & 1:
            b -= 1
            yield data[b-1]
        if a & 1:
            yield data[a-1]
            a += 1
        a >>= 1; b >>= 1
# LCAの計算 (外から呼び出す関数)
def query(u, v):
    fu = F[u]; fv = F[v]
    if fu > fv:
        fu, fv = fv, fu
    return S[min(_query(fu, fv+1))[1]]
memo={}

todo=[[0,[]]]
path=[[]]*n
mi=[1]*n
while todo:
  v,ary=todo.pop()
  path[v]=ary
  mi[v]=0
  for i,nv in ki[v]:
    if mi[nv]==1:
      todo.append([nv,ary+[i]])
      mi[nv]=1
#print(path)
for i in range(n):
  path[i]=set(path[i])
ans=2**(n-1)
for i in range(2**m):
  chk=set(())
  for j in range(m):
    if (i>>j)&1:
      chk.add(j)
  if not chk:continue
  must_w=set(())
  for c in chk:
    u,v=uv[c]
    if (u,v) in memo:
      tmp=memo[(u,v)]
    else:
      dd=query(u,v)
      tmp=path[u].union(path[v])
      tmp=tmp-path[dd]
      memo[(u,v)]=tmp
    must_w=must_w.union(tmp)
  t=n-1-len(must_w)
  if len(chk)%2==1:
    ans-=pow(2,t)
  else:
    ans+=pow(2,t)
print(ans)

Submission status: Time Limit Exceeded

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

n=int(input())
kk=[[] for _ in range(n)]
ki=[[] for _ in range(n)]
for i in range(n-1):
  u,v=map(int,input().split())
  u,v=u-1,v-1
  kk[u].append([i,v])
  kk[v].append([i,u])
m=int(input())
uv=[]
for _ in range(m):
  u,v=map(int,input().split())
  u,v=u-1,v-1
  uv.append([u,v])

todo=[0]
ka=set(())
while todo:
  v=todo.pop()
  ka.add(v)
  for i,nv in kk[v]:
    if nv not in ka:
      ki[v].append([i,nv])
      todo.append(nv)


# n: 頂点数
# ki[v]: 頂点vの子頂点 (親頂点は含まない)
# Euler Tour の構築
S=[]
F=[0]*n
depth=[0]*n
def dfs(v,pare,d):
    F[v]=len(S)
    depth[v]=d
    S.append(v)
    for i,w in ki[v]:
        if w==pare:continue
        dfs(w,v,d+1)
        S.append(v)
dfs(0,-1,0)
#print(S)
# 存在しない範囲は深さが他よりも大きくなるようにする
INF = (n, None)

# LCAを計算するクエリの前計算
M = 2*n
M0 = 2**(M-1).bit_length()
data = [INF]*(2*M0)
for i, v in enumerate(S):
    data[M0-1+i] = (depth[v], i)
for i in range(M0-2, -1, -1):
    data[i] = min(data[2*i+1], data[2*i+2])

# LCAの計算 (generatorで最小値を求める)
def _query(a, b):
    yield INF
    a += M0; b += M0
    while a < b:
        if b & 1:
            b -= 1
            yield data[b-1]
        if a & 1:
            yield data[a-1]
            a += 1
        a >>= 1; b >>= 1
# LCAの計算 (外から呼び出す関数)
def query(u, v):
    fu = F[u]; fv = F[v]
    if fu > fv:
        fu, fv = fv, fu
    return S[min(_query(fu, fv+1))[1]]
d={}

todo=[[0,[]]]
path=[[]]*n
mi=[1]*n
while todo:
  v,ary=todo.pop()
  path[v]=ary
  mi[v]=0
  for i,nv in ki[v]:
    if mi[nv]==1:
      todo.append([nv,ary+[i]])
      mi[nv]=1
#print(path)
for i in range(n):
  path[i]=set(path[i])
ans=2**(n-1)
for i in range(2**m):
  chk=set(())
  for j in range(m):
    if (i>>j)&1:
      chk.add(j)
  if not chk:continue
  must_w=set(())
  for c in chk:
    u,v=uv[c]
    if (u,v) in d:
      tmp=d[(u,v)]
    else:
      dd=query(u,v)
      tmp=path[u].union(path[v])
      tmp=tmp-path[dd]
      d[(u,v)]=tmp
    must_w=must_w.union(tmp)
  t=n-1-len(must_w)
  if len(chk)%2==1:
    ans-=pow(2,t)
  else:
    ans+=pow(2,t)
print(ans)