#pragma comment(linker,"/STACK:100000000,100000000")
#include <stdio.h>
#define LL __int64
const int mod = 1000000007;
const int maxn = 1000003;
struct EDGE{
int to, next;
}edge[maxn*2];
int head[maxn], E, cnt[maxn];
LL jie[maxn], mul[maxn];
void init(int n) {
for(int i = 1;i <= n; i++) head[i] = -1;
E = 0;
}
void newedge(int u, int to) {
edge[E].to = to;
edge[E].next = head[u];
head[u] = E++;
}
LL modstyle(LL x) { // 取余操作,由于取余%很慢的,这样写效率比较好
if(x >= mod) x %= mod;
else if(x < 0) {
x = (x%mod+mod)%mod;
}
return x;
}
// 扩展欧几里得 求逆元
LL exgcd(LL a ,LL b, LL &x, LL &y) {
if(b == 0) {
x = 1; y = 0;
return a;;
}
LL ans = exgcd(b, a%b, y, x);
y = y - a/b*x;
return ans;
}
// 求组合数 C(n,k)
LL cal(int n, int k) {
LL x, y;
LL d = exgcd(jie[n-k]*jie[k], mod, x, y);
x = modstyle(x);
return jie[n]*x%mod;
}
// 第一次DFS统计出每个节点的所有的子树的总结点数cnt[u],子树节点信息传到该节点的情况数mul[u]
void dfs1(int u, int pre) {
cnt[u] = 0;
mul[u] = 1;
for(int i = head[u];i != -1;i = edge[i].next) {
int to = edge[i].to;
if(to != pre) {
dfs1(to, u);
cnt[u] += cnt[to]+1;
mul[u] = modstyle(mul[u]*mul[to]);
}
}
int sum = cnt[u];
for(int i = head[u];i != -1;i = edge[i].next) {
int to = edge[i].to;
if(to != pre) {
mul[u] = modstyle(mul[u]*cal(sum, cnt[to]+1)); // 对于子树的情况利用组合数进行汇聚
sum -= cnt[to]+1;
}
}
}
LL ans = 0;
int n;
void dfs2(int u, int pre) {
if(pre != -1) { // 父节点的信息传到该节点进行更新计算
LL x, y;
LL d = exgcd(cal(n-1, cnt[u]+1), mod, x, y);
x = modstyle(x);
LL cur = mul[pre]*x%mod;
cur = cur*cal(n-1, cnt[u])%mod;
mul[u] = cur;
ans = (ans + cur*cur)%mod;
}
for(int i = head[u];i != -1;i = edge[i].next) {
int to = edge[i].to;
if(to != pre) {
dfs2(to, u);
}
}
}
int main() {
int i, t, u, to;
jie[0] = 1;
for(i = 1;i <= 1000000; i++) {
jie[i] = modstyle(jie[i-1]*i);
}
scanf("%d", &t);
while(t--) {
scanf("%d", &n);
if(n == 1) {
puts("1");
continue;
}
init(n);
for(i = 0;i < n-1; i++) {
scanf("%d%d", &u, &to);
newedge(u, to);
newedge(to, u);
}
dfs1(1, -1);
ans = mul[1]*mul[1]%mod;
dfs2(1, -1);
printf("%I64d\n", ans);
}
return 0;
}
tjut 4661
最新推荐文章于 2016-08-31 17:14:15 发布