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 b_i.
For each k=1, ..., N, solve the problem below:

Consider writing a number on each vertex in the tree in the following manner:

First, write 1 on Vertex k.

Then, for each of the numbers 2, ..., N in this order, write the number on the vertex chosen as follows:

Choose a vertex that still does not have a number written on it and is adjacent to a vertex with a number already written on it. If there are multiple such vertices, choose one of them at random.

Find the number of ways in which we can write the numbers on the vertices, modulo (10^9+7).

Constraints

2 \leq N \leq 2 \times 10^5

1 \leq a_i,b_i \leq N

The given graph is a tree.

Input

Input is given from Standard Input in the following format:

N
a_1 b_1
:
a_{N-1} b_{N-1}

Output

For each k=1, 2, ..., N in this order, print a line containing the answer to the problem.

Sample Input 1

3
1 2
1 3

Sample Output 1

2
1
1

The graph in this input is as follows:

For k=1, there are two ways in which we can write the numbers on the vertices, as follows:

Writing 1, 2, 3 on Vertex 1, 2, 3, respectively

Writing 1, 3, 2 on Vertex 1, 2, 3, respectively

Sample Input 2

2
1 2

Sample Output 2

1
1

The graph in this input is as follows:

Sample Input 3

5
1 2
2 3
3 4
3 5

Sample Output 3

2
8
12
3
3

The graph in this input is as follows:

Sample Input 4

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

Sample Output 4

40
280
840
120
120
504
72
72

The graph in this input is as follows:



Sample input:
3
1 2
1 3


Sample output:
2
1
1

Submission status: Time Limit Exceeded

Solution code:
import sys
sys.setrecursionlimit(10**7) #再帰関数の上限,10**5以上の場合python
import math
from copy import copy, deepcopy
from copy import deepcopy as dcp
from operator import itemgetter
from bisect import bisect_left, bisect, bisect_right#2分探索
#bisect_left(l,x), bisect(l,x)#aはソート済みである必要あり。aの中からx未満の要素数を返す。rightだと以下
from collections import deque
#deque(l), pop(), append(x), popleft(), appendleft(x)
##listでqueの代用をするとO(N)の計算量がかかってしまうので注意
from collections import Counter#文字列を個数カウント辞書に、
#S=Counter(l),S.most_common(x),S.keys(),S.values(),S.items()
from itertools import accumulate#累積和
#list(accumulate(l))
from heapq import heapify,heappop,heappush
#heapify(q),heappush(q,a),heappop(q) #q=heapify(q)としないこと、返り値はNone
#import fractions#古いatcoderコンテストの場合GCDなどはここからimportする
from functools import lru_cache#pypyでもうごく
#@lru_cache(maxsize = None)#maxsizeは保存するデータ数の最大値、2**nが最も高効率

def input(): return sys.stdin.readline()[:-1]
def printl(li): _=print(*li, sep="\n") if li else None
def argsort(s, return_sorted=False): 
    inds=sorted(range(len(s)), key=lambda k: s[k])
    if return_sorted: return inds, [s[i] for i in inds]
    return inds
def alp2num(c,cap=False): return ord(c)-97 if not cap else ord(c)-65
def num2alp(i,cap=False): return chr(i+97) if not cap else chr(i+65)
def matmat(A,B):
    K,N,M=len(B),len(A),len(B[0])
    return [[sum([(A[i][k]*B[k][j]) for k in range(K)]) for j in range(M)] for i in range(N)]
def matvec(M,v):
    N,size=len(v),len(M)
    return [sum([M[i][j]*v[j] for j in range(N)]) for i in range(size)]
def T(M):
    n,m=len(M),len(M[0])
    return [[M[j][i] for j in range(n)] for i in range(m)]

        
class modint:#add:和,mul:積,pow:累乗,div:商(modと互いに素であること)
    def __init__(self,x,mod=1000000007): 
        if isinstance(x, modint):x=x.x
        self.x, self.mod= x%mod, mod

    def __str__(self):
        return str(self.x)

    def __add__(self, a):
        if isinstance(a, modint):a=a.x
        return modint(self.x+a)

    def __radd__(self, a):return self.__add__(a)

    def __iadd__(self, a):
        self.x=self.__add__(a)
        return self

    def __sub__(self, a):
        if isinstance(a, modint):a=a.x
        return self.__add__(-a)
    
    def __rsub__(self, a):return (a-self.x)%mod

    def __isub__(self, a):
        return self.__iadd__(-a)

    def __mul__(self, c):
        if isinstance(c, modint):c=c.x
        return modint(self.x*(c%self.mod))
    
    def __rmul__(self, c):return self.__mul__(c)
    
    def __imul__(self, c):
        return self.__mul__(c)

    def __pow__(self,p):
        if isinstance(p, modint):p=p.x
        return modint(pow(self.x,p,self.mod))
    
    def __ipow__(self,p):
        return self.__pow__(p)
        

    def __truediv__(self, d):
        if isinstance(d, modint):d=d.x
        u,v,a,b=1,0,d,self.mod
        while b:
            t=a//b
            a-=t*b
            a,b,u,v=b,a,v,u-t*v
        if a!=1: print("not 素")
        return modint(self.x*(u%self.mod),self.mod)

    def __itruediv__(self, d):
        self.x=self.__truediv__(d)
        return self

    def __eq__(self, target):
        if isinstance(target, modint):
            return self.x==target.x
        return self.x==target%self.mod
    

class comb:
    def __init__(self,N,mod=10**9+7):#コンビネーションnCrをmodで求める、Nは最大のn 
        self.mod=mod
        self.fact=[0]*(N+1)
        self.ifact=[0]*(N+1)
        fact,ifact=self.fact,self.ifact
        fact[0],fact[1],ifact[0],ifact[1]=1,1,1,1
        for i in range(2,N+1):
            x=(fact[i-1]*i)%mod
            fact[i]=x
            ifact[i]=self.extgcd1(x,mod)

    @lru_cache(maxsize = None)
    def extgcd1(self,a0,b0):#計算量log(b0),フェルマーの小定理より早い
        u,v,a,b=1,0,a0,b0
        while b:
            t,a=divmod(a,b)
            a,b,u,v=b,a,v,u-t*v
        if a!=1: 
            print("not 素")
            return -1
        return u%b0

    @lru_cache(maxsize = None)
    def comb(self,n,r): return (self.fact[n]*self.ifact[r]%self.mod)*self.ifact[n-r]%self.mod

    @lru_cache(maxsize = None)
    def mulcomb(self,n,*rs):#n!/(r1!*r2!*r3!*...)
        ans=self.fact[n]
        for r in rs: ans=(ans*self.ifact[r])%self.mod
        return ans

class rerooting:#全方位木
    def __init__(self,N,edge):#単位元self.unitとモノイドdef funcを設定すること,
        #dics[親][根（親の隣接点)]=その部分木での値
        self.unit=(modint(1),0)
        self.edge=edge
        self.cb=comb(N)
        self.par=[-1]*N
        self.N=N
        self.visited=[0]*N
        self.dics=[dict() for _ in range(N)]
        self.ikigake=[]
        self.tot=[self.unit]*N
        
    def func(self,x,y):
        ans=modint(1)
        slist=[]
        for p,s in (x,y):
            ans*=p
            slist.append(s)
        ssum=sum(slist)
        #print(x,y,slist)
        ans*=self.cb.mulcomb(ssum,*slist)
        return ans,ssum 

    def addnode(self,x):#部分木に親のノードを結合する処理,dfsとforwardに出現
        p,s=x
        return p,s+1

    def _dfs(self,e,pa):
        edge=self.edge
        self.par[e]=pa
        self.ikigake.append(e)
        ans=self.unit
        for ne in edge[e]:
            if self.par[ne]!=-1:
                continue
            ans=self.func(ans,self.addnode(self._dfs(ne,e)))
            #print(ans)
        if pa!=e:
            self.dics[pa][e]=ans
        
        return ans
    
    def forward(self,start):
        self._dfs(start,start)
        for e in self.ikigake:
            pa=self.par[e]
            nes=list(self.dics[e].keys())
            nvals=list(self.dics[e].values())
            l=len(nes)
            aleft=[self.unit]
            aright=[self.unit]
            cleft=self.unit
            cright=self.unit
            for i in range(l-1):
                cleft=self.func(cleft,self.addnode(nvals[i]))
                cright=self.func(cright,self.addnode(nvals[-i-1]))
                aleft.append(cleft)
                aright.append(cright)
            self.tot[e]=self.func(aright[-1],self.addnode(nvals[0]))
            for i,ne in enumerate(nes):
                if ne==pa:
                    continue
                p,s=self.func(aleft[i],aright[-1-i])
                self.dics[ne][e]=(p,s)


def main():
    mod = 1000000007
    #w.sort(key=itemgetter(1),reversed=True)  #二個目の要素で降順並び替え

    N = int(input())
    #N, K = map(int, input().split())
    #A = tuple(map(int, input().split())) #1行ベクトル
    #L = tuple(int(input()) for i in range(N)) #改行ベクトル
    #S = tuple(tuple(map(int, input().split())) for i in range(N)) #改行行列

    def tree_init(N):
        edgelist = [[] for _ in range(N)]
        elist=set()
        for a, b in [map(int, input().split()) for i in range(N-1)]:#木じゃない場合N-1をNに変える
            edgelist[a-1].append(b-1)#ノードの番号が0から始まる場合-1を消す
            edgelist[b-1].append(a-1)
            elist.add((a-1,b-1))
        return edgelist,elist

    edge,elist=tree_init(N)
    cb=comb(N)
    rt=rerooting(N,edge)
    rt.forward(0)
    #print(rt.dics)


    for a in range(N):
        print(rt.tot[a][0])

    



if __name__ == "__main__":
    main()

Submission status: Time Limit Exceeded

Solution code:
import sys
sys.setrecursionlimit(10**7) #再帰関数の上限,10**5以上の場合python
import math
from copy import copy, deepcopy
from copy import deepcopy as dcp
from operator import itemgetter
from bisect import bisect_left, bisect, bisect_right#2分探索
#bisect_left(l,x), bisect(l,x)#aはソート済みである必要あり。aの中からx未満の要素数を返す。rightだと以下
from collections import deque
#deque(l), pop(), append(x), popleft(), appendleft(x)
##listでqueの代用をするとO(N)の計算量がかかってしまうので注意
from collections import Counter#文字列を個数カウント辞書に、
#S=Counter(l),S.most_common(x),S.keys(),S.values(),S.items()
from itertools import accumulate#累積和
#list(accumulate(l))
from heapq import heapify,heappop,heappush
#heapify(q),heappush(q,a),heappop(q) #q=heapify(q)としないこと、返り値はNone
#import fractions#古いatcoderコンテストの場合GCDなどはここからimportする
from functools import lru_cache#pypyでもうごく
#@lru_cache(maxsize = None)#maxsizeは保存するデータ数の最大値、2**nが最も高効率

def input(): return sys.stdin.readline()[:-1]
def printl(li): _=print(*li, sep="\n") if li else None
def argsort(s, return_sorted=False): 
    inds=sorted(range(len(s)), key=lambda k: s[k])
    if return_sorted: return inds, [s[i] for i in inds]
    return inds
def alp2num(c,cap=False): return ord(c)-97 if not cap else ord(c)-65
def num2alp(i,cap=False): return chr(i+97) if not cap else chr(i+65)
def matmat(A,B):
    K,N,M=len(B),len(A),len(B[0])
    return [[sum([(A[i][k]*B[k][j]) for k in range(K)]) for j in range(M)] for i in range(N)]
def matvec(M,v):
    N,size=len(v),len(M)
    return [sum([M[i][j]*v[j] for j in range(N)]) for i in range(size)]
def T(M):
    n,m=len(M),len(M[0])
    return [[M[j][i] for j in range(n)] for i in range(m)]

        
class modint:#add:和,mul:積,pow:累乗,div:商(modと互いに素であること)
    def __init__(self,x,mod=1000000007): 
        if isinstance(x, modint):x=x.x
        self.x, self.mod= x%mod, mod

    def __str__(self):
        return str(self.x)

    def __add__(self, a):
        if isinstance(a, modint):a=a.x
        return modint(self.x+a)

    def __radd__(self, a):return self.__add__(a)

    def __iadd__(self, a):
        self.x=self.__add__(a)
        return self

    def __sub__(self, a):
        if isinstance(a, modint):a=a.x
        return self.__add__(-a)
    
    def __rsub__(self, a):return (a-self.x)%mod

    def __isub__(self, a):
        return self.__iadd__(-a)

    def __mul__(self, c):
        if isinstance(c, modint):c=c.x
        return modint(self.x*(c%self.mod))
    
    def __rmul__(self, c):return self.__mul__(c)
    
    def __imul__(self, c):
        return self.__mul__(c)

    def __pow__(self,p):
        if isinstance(p, modint):p=p.x
        return modint(pow(self.x,p,self.mod))
    
    def __ipow__(self,p):
        return self.__pow__(p)
        

    def __truediv__(self, d):
        if isinstance(d, modint):d=d.x
        u,v,a,b=1,0,d,self.mod
        while b:
            t=a//b
            a-=t*b
            a,b,u,v=b,a,v,u-t*v
        if a!=1: print("not 素")
        return modint(self.x*(u%self.mod))

    def __itruediv__(self, d):
        self.x=self.__truediv__(d)
        return self

    def __eq__(self, target):
        if isinstance(target, modint):
            return self.x==target.x
        return self.x==target%self.mod
    

class comb:
    def __init__(self,N,mod=10**9+7):#コンビネーションnCrをmodで求める、Nは最大のn 
        self.mod=mod
        self.fact=[0]*(N+1)
        self.ifact=[0]*(N+1)
        fact,ifact=self.fact,self.ifact
        fact[0],fact[1],ifact[0],ifact[1]=1,1,1,1
        for i in range(2,N+1):
            x=(fact[i-1]*i)%mod
            fact[i]=x
            ifact[i]=self.extgcd1(x,mod)

    @lru_cache(maxsize = None)
    def extgcd1(self,a0,b0):#計算量log(b0),フェルマーの小定理より早い
        u,v,a,b=1,0,a0,b0
        while b:
            t,a=divmod(a,b)
            a,b,u,v=b,a,v,u-t*v
        if a!=1: 
            print("not 素")
            return -1
        return u%b0

    @lru_cache(maxsize = None)
    def comb(self,n,r): return (self.fact[n]*self.ifact[r]%self.mod)*self.ifact[n-r]%self.mod

    @lru_cache(maxsize = None)
    def mulcomb(self,n,*rs):#n!/(r1!*r2!*r3!*...)
        ans=self.fact[n]
        for r in rs: ans=(ans*self.ifact[r])%self.mod
        return ans

class rerooting:#全方位木
    def __init__(self,N,edge):#単位元self.unitとモノイドdef funcを設定すること,
        #dics[親][根（親の隣接点)]=その部分木での値
        self.unit=(modint(1),0)
        self.edge=edge
        self.cb=comb(N)
        self.par=[-1]*N
        self.N=N
        self.visited=[0]*N
        self.dics=[dict() for _ in range(N)]
        self.ikigake=[]
        self.tot=[self.unit]*N
        
    def func(self,x,y):
        ans=modint(1)
        slist=[]
        for p,s in (x,y):
            ans*=p
            slist.append(s)
        ssum=sum(slist)
        #print(x,y,slist)
        ans*=self.cb.mulcomb(ssum,*slist)
        return ans,ssum 

    def addnode(self,x):#部分木に親のノードを結合する処理,dfsとforwardに出現
        p,s=x
        return p,s+1

    def _dfs(self,e,pa):
        edge=self.edge
        self.par[e]=pa
        self.ikigake.append(e)
        ans=self.unit
        for ne in edge[e]:
            if self.par[ne]!=-1:
                continue
            ans=self.func(ans,self.addnode(self._dfs(ne,e)))
            #print(ans)
        if pa!=e:
            self.dics[pa][e]=ans
        
        return ans
    
    def forward(self,start):
        self._dfs(start,start)
        for e in self.ikigake:
            pa=self.par[e]
            nes=list(self.dics[e].keys())
            nvals=list(self.dics[e].values())
            l=len(nes)
            aleft=[self.unit]
            aright=[self.unit]
            cleft=self.unit
            cright=self.unit
            for i in range(l-1):
                cleft=self.func(cleft,self.addnode(nvals[i]))
                cright=self.func(cright,self.addnode(nvals[-i-1]))
                aleft.append(cleft)
                aright.append(cright)
            self.tot[e]=self.func(aright[-1],self.addnode(nvals[0]))
            for i,ne in enumerate(nes):
                if ne==pa:
                    continue
                p,s=self.func(aleft[i],aright[-1-i])
                self.dics[ne][e]=(p,s)


def main():
    mod = 1000000007
    #w.sort(key=itemgetter(1),reversed=True)  #二個目の要素で降順並び替え

    N = int(input())
    #N, K = map(int, input().split())
    #A = tuple(map(int, input().split())) #1行ベクトル
    #L = tuple(int(input()) for i in range(N)) #改行ベクトル
    #S = tuple(tuple(map(int, input().split())) for i in range(N)) #改行行列

    def tree_init(N):
        edgelist = [[] for _ in range(N)]
        elist=set()
        for a, b in [map(int, input().split()) for i in range(N-1)]:#木じゃない場合N-1をNに変える
            edgelist[a-1].append(b-1)#ノードの番号が0から始まる場合-1を消す
            edgelist[b-1].append(a-1)
            elist.add((a-1,b-1))
        return edgelist,elist

    edge,elist=tree_init(N)
    cb=comb(N)
    rt=rerooting(N,edge)
    rt.forward(0)
    #print(rt.dics)
    def solve(a,b):
        p1,s1=rt.dics[a][b]
        p2,s2=rt.dics[b][a]
        ans=(cb.comb((s1+s2),s1)*p1*p2)%mod
        #print(a,b,p1,p2,s1,s2,ans)
        return ans

    for a in range(N):
        print(rt.tot[a][0])

    



if __name__ == "__main__":
    main()

Submission status: Time Limit Exceeded

Solution code:
import sys
sys.setrecursionlimit(10**7) #再帰関数の上限,10**5以上の場合python
import math
from copy import copy, deepcopy
from copy import deepcopy as dcp
from operator import itemgetter
from bisect import bisect_left, bisect, bisect_right#2分探索
#bisect_left(l,x), bisect(l,x)#aはソート済みである必要あり。aの中からx未満の要素数を返す。rightだと以下
from collections import deque
#deque(l), pop(), append(x), popleft(), appendleft(x)
##listでqueの代用をするとO(N)の計算量がかかってしまうので注意
from collections import Counter#文字列を個数カウント辞書に、
#S=Counter(l),S.most_common(x),S.keys(),S.values(),S.items()
from itertools import accumulate#累積和
#list(accumulate(l))
from heapq import heapify,heappop,heappush
#heapify(q),heappush(q,a),heappop(q) #q=heapify(q)としないこと、返り値はNone
#import fractions#古いatcoderコンテストの場合GCDなどはここからimportする
from functools import lru_cache#pypyでもうごく
#@lru_cache(maxsize = None)#maxsizeは保存するデータ数の最大値、2**nが最も高効率

def input(): return sys.stdin.readline()[:-1]
def printl(li): _=print(*li, sep="\n") if li else None
def argsort(s, return_sorted=False): 
    inds=sorted(range(len(s)), key=lambda k: s[k])
    if return_sorted: return inds, [s[i] for i in inds]
    return inds
def alp2num(c,cap=False): return ord(c)-97 if not cap else ord(c)-65
def num2alp(i,cap=False): return chr(i+97) if not cap else chr(i+65)
def matmat(A,B):
    K,N,M=len(B),len(A),len(B[0])
    return [[sum([(A[i][k]*B[k][j]) for k in range(K)]) for j in range(M)] for i in range(N)]
def matvec(M,v):
    N,size=len(v),len(M)
    return [sum([M[i][j]*v[j] for j in range(N)]) for i in range(size)]
def T(M):
    n,m=len(M),len(M[0])
    return [[M[j][i] for j in range(n)] for i in range(m)]

    
class modint:#商をとるときはmodとdが互いに素であること
    def __init__(self,x,mod=1000000007): 
        self.x, self.mod= x%mod, mod

    def __str__(self):
        return str(self.x)

    def __add__(self, a):
        if isinstance(a, modint):a=a.x
        return (self.x+a)%self.mod

    def __radd__(self, a):return self.__add__(a)

    def __iadd__(self, a):
        self.x=self.__add__(a)
        return self

    def __sub__(self, a):
        if isinstance(a, modint):a=a.x
        return self.__add__(-a)
    
    def __rsub__(self, a):return (a-self.x)%self.mod

    def __isub__(self, a):
        return self.__iadd__(-a)

    def __mul__(self, c):
        if isinstance(c, modint):c=c.x
        return (self.x*(c%self.mod))%self.mod
    
    def __rmul__(self, c):return self.__mul__(c)
    
    def __imul__(self, c):
        self.x=self.__mul__(c)
        return self

    def __pow__(self,p):
        if isinstance(p, modint):p=p.x
        return pow(self.x,p,self.mod)
    
    def __ipow__(self,p):
        self.x=self.__pow__(p)
        return self

    def __truediv__(self, d):
        if isinstance(d, modint):d=d.x
        u,v,a,b=1,0,d,self.mod
        while b:
            t=a//b
            a-=t*b
            a,b,u,v=b,a,v,u-t*v
        if a!=1: print("not 素")
        return int((self.x*(u%self.mod))%self.mod)

    def __itruediv__(self, d):
        self.x=self.__truediv__(d)
        return self

    def __eq__(self, target):
        if isinstance(target, modint):
            return self.x==target.x
        return self.x==target%self.mod
 
class comb:
    def __init__(self,N,mod=10**9+7):#コンビネーションnCrをmodで求める、Nは最大のn 
        self.mod=mod
        self.fact=[0]*(N+1)
        self.ifact=[0]*(N+1)
        fact,ifact=self.fact,self.ifact
        fact[0],fact[1],ifact[0],ifact[1]=1,1,1,1
        for i in range(2,N+1):
            x=(fact[i-1]*i)%mod
            fact[i]=x
            ifact[i]=self.extgcd1(x,mod)

    @lru_cache(maxsize = None)
    def extgcd1(self,a0,b0):#計算量log(b0),フェルマーの小定理より早い
        u,v,a,b=1,0,a0,b0
        while b:
            t,a=divmod(a,b)
            a,b,u,v=b,a,v,u-t*v
        if a!=1: 
            print("not 素")
            return -1
        return u%b0

    @lru_cache(maxsize = None)
    def comb(self,n,r): return (self.fact[n]*self.ifact[r]%self.mod)*self.ifact[n-r]%self.mod

    @lru_cache(maxsize = None)
    def mulcomb(self,n,*rs):#n!/(r1!*r2!*r3!*...)
        ans=self.fact[n]
        for r in rs: ans=(ans*self.ifact[r])%self.mod
        return ans

class rerooting:#全方位木
    def __init__(self,N,edge):#単位元self.unitとモノイドdef funcを設定すること,
        #dics[親][根（親の隣接点)]=その部分木での値
        self.unit=(modint(1),0)
        self.edge=edge
        self.cb=comb(N)
        self.par=[-1]*N
        self.N=N
        self.visited=[0]*N
        self.dics=[dict() for _ in range(N)]
        self.ikigake=[]
        self.tot=[self.unit]*N
        
    def func(self,x,y):
        ans=modint(1)
        slist=[]
        for p,s in (x,y):
            ans*=p
            slist.append(s)
        ssum=sum(slist)
        #print(x,y,slist)
        ans*=self.cb.mulcomb(ssum,*slist)
        return ans,ssum 

    def addnode(self,x):#部分木に親のノードを結合する処理,dfsとforwardに出現
        p,s=x
        return p,s+1

    def _dfs(self,e,pa):
        edge=self.edge
        self.par[e]=pa
        self.ikigake.append(e)
        ans=self.unit
        for ne in edge[e]:
            if self.par[ne]!=-1:
                continue
            #print(e,ne,x)
            ans=self.func(ans,self.addnode(self._dfs(ne,e)))
            #print(ans)
        if pa!=e:
            self.dics[pa][e]=ans
        
        return ans
    
    def forward(self,start):
        self._dfs(start,start)
        for e in self.ikigake:
            pa=self.par[e]
            nes=list(self.dics[e].keys())
            nvals=list(self.dics[e].values())
            l=len(nes)
            aleft=[self.unit]
            aright=[self.unit]
            cleft=self.unit
            cright=self.unit
            for i in range(l-1):
                cleft=self.func(cleft,self.addnode(nvals[i]))
                cright=self.func(cright,self.addnode(nvals[-i-1]))
                aleft.append(cleft)
                aright.append(cright)
            self.tot[e]=self.func(aright[-1],self.addnode(nvals[0]))
            for i,ne in enumerate(nes):
                if ne==pa:
                    continue
                p,s=self.func(aleft[i],aright[-1-i])
                self.dics[ne][e]=(p,s)


def main():
    mod = 1000000007
    #w.sort(key=itemgetter(1),reversed=True)  #二個目の要素で降順並び替え

    N = int(input())
    #N, K = map(int, input().split())
    #A = tuple(map(int, input().split())) #1行ベクトル
    #L = tuple(int(input()) for i in range(N)) #改行ベクトル
    #S = tuple(tuple(map(int, input().split())) for i in range(N)) #改行行列

    def tree_init(N):
        edgelist = [[] for _ in range(N)]
        elist=set()
        for a, b in [map(int, input().split()) for i in range(N-1)]:#木じゃない場合N-1をNに変える
            edgelist[a-1].append(b-1)#ノードの番号が0から始まる場合-1を消す
            edgelist[b-1].append(a-1)
            elist.add((a-1,b-1))
        return edgelist,elist

    edge,elist=tree_init(N)
    cb=comb(N)
    rt=rerooting(N,edge)
    rt.forward(0)
    #print(rt.dics)
    def solve(a,b):
        p1,s1=rt.dics[a][b]
        p2,s2=rt.dics[b][a]
        ans=(cb.comb((s1+s2),s1)*p1*p2)%mod
        #print(a,b,p1,p2,s1,s2,ans)
        return ans

    for a in range(N):
        print(rt.tot[a][0])

    



if __name__ == "__main__":
    main()

Submission status: Time Limit Exceeded

Solution code:
#!/usr/bin/env python3
import sys
from collections import defaultdict
from functools import lru_cache

sys.setrecursionlimit(10**8)
INF = float("inf")

MOD = 1000000007  # type: int


class Graph(object):
    def __init__(self, N):
        self.N = N
        self.E = defaultdict(list)

    def add_edge(self, src, dest, w=1):
        self.E[src].append((dest, w))
        self.E[dest].append((src, w))


def div(a, b):
    return (a * pow(b, MOD-2, MOD)) % MOD


class Combination(object):

    def __init__(self, N, mod=MOD):
        fac, finv, inv = [0]*(N+1), [0]*(N+1), [0]*(N+1)
        fac[:2] = 1, 1
        finv[:2] = 1, 1
        inv[1] = 1
        for i in range(2, N+1):
            fac[i] = fac[i-1]*i % mod
            inv[i] = -inv[mod % i]*(mod//i) % mod
            finv[i] = finv[i-1]*inv[i] % mod
        self.N = N
        self.MOD = mod
        self.fac = fac
        self.finv = finv
        self.inv = inv

    @lru_cache(maxsize=None)
    def __call__(self, n, k):
        # print("A", n, k)
        if n < k:
            return 0
        if n < 0 or k < 0:
            return 0
        fac = self.fac
        finv = self.finv
        mod = self.MOD
        # print("B", n, k, n-k)
        return fac[n] * (finv[k]*finv[n-k] % mod) % mod


class DP(object):
    def __init__(self, dp0=1, t0=0):
        self.dp = dp0
        self.t = t0
        pass

    def __iadd__(self, a):
        self.dp *= cmb(self.t+a.t, a.t)
        self.dp *= a.dp
        self.t += a.t
        return self

    def __sub__(self, a):
        dp = DP()
        dp.dp = div(self.dp, cmb(self.t-1, a.t))
        dp.dp = div(dp.dp, a.dp)
        dp.t = self.t - a.t
        return dp

    def add_root(self):
        self.t += 1
        return self

    def __str__(self):
        return "({}通り, {}個)".format(self.dp, self.t)


def solve(N: int, a: "List[int]", b: "List[int]"):
    # print(div(3, 2))

    # 全方位木DPをやるぞ！
    # 1. 木DPによって頂点ごとにhogeを求める
    # 2. 木DPで求めたhogeを使って、上手く求める

    # グラフの構築
    g = Graph(N)
    for aa, bb in zip(a, b):
        g.add_edge(aa-1, bb-1)

    # 組み合わせの初期化
    cmb = Combination(N)

    dp = [1]*N                  # 節点vを根とした部分木の塗り方dp[v]
    size = [0]*N                # 節点vを根とした部分木のサイズsize[v]+1

    # 木DPを行うDFS
    def dfs(v, p=-1):
        # print("dfs start", v, p)
        for u, _ in g.E[v]:
            if u == p:
                continue
            dfs(u, v)

            # print("dfs", u, v)
            size[v] += size[u]+1
            dp[v] *= cmb(size[v], size[u]+1)
            dp[v] %= MOD
            dp[v] *= dp[u]
            dp[v] %= MOD
        # print("dfs end", v, (size[v], dp[v]))
        return

    dfs(0, -1)
    # print(*[(d, s) for d, s in zip(dp, size)])

    # 節点0には木の根としての値を求めた。
    # 0以外の節点には部分木の根としての値を求めた。
    # 木の根としての値を求めた節点を親としてもつ節点は、自身を木の根とした値を求めることができる

    # 全方位木DPを行うBFS
    def bfs(v, p=-1):
        for u, _ in g.E[v]:
            if u == p:
                continue
            d = div(dp[v], cmb(size[v], size[u]+1))
            d = div(d, dp[u])
            dp[u] *= cmb(N-1, size[u])
            dp[u] %= MOD
            dp[u] *= d
            dp[u] %= MOD
            size[u] = N-1
            bfs(u, v)
    bfs(0, -1)

    for v in dp:
        print(v)
    return


def main():

    def iterate_tokens():
        for line in sys.stdin:
            for word in line.split():
                yield word
    tokens = iterate_tokens()
    N = int(next(tokens))  # type: int
    a = [int()] * (N - 1)  # type: "List[int]"
    b = [int()] * (N - 1)  # type: "List[int]"
    for i in range(N - 1):
        a[i] = int(next(tokens))
        b[i] = int(next(tokens))
    solve(N, a, b)


if __name__ == '__main__':
    main()

Submission status: Time Limit Exceeded

Solution code:
#!/usr/bin/env python3
import sys
from collections import defaultdict
import functools

sys.setrecursionlimit(10**8)
INF = float("inf")

MOD = 1000000007  # type: int


class Graph(object):
    def __init__(self, N):
        self.N = N
        self.E = defaultdict(list)

    def add_edge(self, src, dest, w=1):
        self.E[src].append((dest, w))
        self.E[dest].append((src, w))


def div(a, b):
    return (a * pow(b, MOD-2, MOD)) % MOD


class Combination(object):

    def __init__(self, N, mod=MOD):
        fac, finv, inv = [0]*(N+1), [0]*(N+1), [0]*(N+1)
        fac[:2] = 1, 1
        finv[:2] = 1, 1
        inv[1] = 1
        for i in range(2, N+1):
            fac[i] = fac[i-1]*i % mod
            inv[i] = -inv[mod % i]*(mod//i) % mod
            finv[i] = finv[i-1]*inv[i] % mod
        self.N = N
        self.MOD = mod
        self.fac = fac
        self.finv = finv
        self.inv = inv

    def __call__(self, n, k):
        # print("A", n, k)
        if n < k:
            return 0
        if n < 0 or k < 0:
            return 0
        fac = self.fac
        finv = self.finv
        mod = self.MOD
        # print("B", n, k, n-k)
        return fac[n] * (finv[k]*finv[n-k] % mod) % mod


cmb = None


class DP(object):
    def __init__(self, dp0=1, t0=0):
        self.dp = dp0
        self.t = t0
        pass

    def __iadd__(self, a):
        # print("+comb", self.t+a.t, a.t)
        self.dp *= cmb(self.t+a.t, a.t)
        # print("??")
        self.dp *= a.dp
        self.t += a.t
        return self

    def __sub__(self, a):
        dp = DP()
        dp.dp = div(self.dp, cmb(self.t-1, a.t))
        dp.dp = div(dp.dp, a.dp)
        dp.t = self.t - a.t
        return dp

    def add_root(self):
        self.t += 1
        return self

    def __str__(self):
        return "({}通り, {}個)".format(self.dp, self.t)


def solve(N: int, a: "List[int]", b: "List[int]"):
    # print(div(3, 2))

    # 全方位木DPをやるぞ！
    # 1. 木DPによって頂点ごとにhogeを求める
    # 2. 木DPで求めたhogeを使って、上手く求める

    # グラフの構築
    g = Graph(N)
    for aa, bb in zip(a, b):
        g.add_edge(aa-1, bb-1)

    # 組み合わせの初期化
    global cmb
    cmb = Combination(N)

    dp = [DP() for _ in range(N)]

    # 木DPを行うDFS
    def dfs(v, p=-1):
        # print("dfs", v, p)
        for u, _ in g.E[v]:
            if u == p:
                continue
            dfs(u, v)
            # print(*dp)
            dp[v] += dp[u]
        dp[v].add_root()
        # print("dfs end", v, dp[v])
        return

    dfs(0, -1)
    # print(*dp)

    # 節点0には木の根としての値を求めた。
    # 0以外の節点には部分木の根としての値を求めた。
    # 木の根としての値を求めた節点を親としてもつ節点は、自身を木の根とした値を求めることができる

    # 全方位木DPを行うBFS
    def bfs(v, p=-1):
        # print("bfs", v, p)
        for u, _ in g.E[v]:
            if u == p:
                continue
            v_as_child = (dp[v]-dp[u])
            # print("更新前", u, dp[u])
            # print("親としての", v, dp[v])
            # print("子としての", v, v_as_child)
            dp[u].t -= 1
            dp[u] += v_as_child
            dp[u].t += 1
            # print("全方位木DP", u, dp[u])
            # print("--")
            # return
            bfs(u, v)

    bfs(0, -1)

    for v in dp:
        print(v.dp)
    return


def main():

    def iterate_tokens():
        for line in sys.stdin:
            for word in line.split():
                yield word
    tokens = iterate_tokens()
    N = int(next(tokens))  # type: int
    a = [int()] * (N - 1)  # type: "List[int]"
    b = [int()] * (N - 1)  # type: "List[int]"
    for i in range(N - 1):
        a[i] = int(next(tokens))
        b[i] = int(next(tokens))
    solve(N, a, b)


if __name__ == '__main__':
    main()