4835: [Lydsy2017年4月月赛]遗忘之树
Time Limit: 3 Sec Memory Limit: 128 MB
Submit: 120 Solved: 53
[Submit][Status][Discuss]
Description
定义任意两点之间存在唯一路径的无向图是树。对于一棵n个点的树,如果删掉某个点u之后每个连通块的大小均不
超过n/2,那么称u为这棵树的重心。现在有一棵n个点的树T,利用过程P来构造一个n个点的有向图G,初始G没有边
。现在对T调用过程P,P的内容如下:
1:删去u,对每个连通块递归调用过程P;
2:对每个连通块,如果它的标号最小的重心为v,那么在图G中连一条u到v的有向边。
3:现在小Q同学手里有一个图G,但是不记得原来T的样子了,希望你能通过G来恢复T,但是可能得到的T会有很多种
你只需要告诉小Q同学可能的T的个数。
两棵树被认为是不同的,当且仅当存在一对点(u,v),使得u和v在一棵树中有边,在另一棵树中没有边。
Input
第一行是一个整数T(1≤T≤1000),表示测试数据的组数。
对于每组测试数据:
第一行是两个整数n和m(2≤n,m≤100000),表示G的点数的边数。
接下来m行,每行是两个整数u和v(1≤u,v≤n),表示有一条从u到v的有向边。
保证对于每组测试数据,至少存在一棵树T,使得对T调用过程P之后可以得到G
并且所有测试数据的n之和、m之和均不超过10^6。
Output
对于每组测试数据,输出一行一个非负整数,表示这组数据的答案对(10^9+7)取模的值。
Sample Input
2
3 2
1 2
1 3
4 3
1 3
2 1
2 4
Sample Output
1
1
HINT
Source
鸣谢Tangjz提供试题
定义状态 f[i] 为在重心树内以 i 为根的子树中合法方案数
那么对于每个儿子,可以用乘法原理乘起来
每个儿子只需考虑有多少点能和当前点直接连边
一个子树中的点不能和当前点连边,当且仅当连了以后重心改变
先特判会不会出现重心改变的情况
有多少编号更小的点可以暴力
因为一个点的深度只有O(logn)
总复杂度 O(nlogn)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int maxn = 1E5 + 10;
typedef long long LL;
const LL mo = 1000000007;
int n,m,T,rt,f[maxn],nex[maxn],last[maxn],siz[maxn];
bool vis[maxn];
vector <int> v[maxn];
#define Mul(x,y) (1LL * (x) * (y) % mo)
inline int getint()
{
char ch = getchar(); int ret = 0;
while (ch < '0' || '9' < ch) ch = getchar();
while ('0' <= ch && ch <= '9')
ret = ret * 10 + ch - '0',ch = getchar();
return ret;
}
inline void Dfs(int x)
{
siz[x] = f[x] = 1; last[x] = x; nex[x] = 0;
for (int i = 0; i < v[x].size(); i++)
{
int y = v[x][i]; Dfs(y); siz[x] += siz[y];
}
bool flag = !(siz[x] & 1); int tmp = siz[x] >> 1;
for (int i = 0; i < v[x].size(); i++)
{
int y = v[x][i],k = 0;
if (flag && siz[y] == tmp)
{
for (int g = y; g; g = nex[g])
if (g > x) ++k;
}
else k = siz[y];
f[x] = Mul(f[x],Mul(f[y],k));
nex[last[x]] = y; last[x] = last[y];
}
}
inline void Solve()
{
n = getint(); m = getint();
while (m--)
{
int x = getint(),y = getint();
v[x].push_back(y); vis[y] = 1;
}
for (int i = 1; i <= n; i++) if (!vis[i]) {rt = i; break;}
Dfs(rt); printf("%d\n",f[rt]);
}
inline void Clear()
{
for (int i = 1; i <= n; i++)
v[i].clear(),vis[i] = 0;
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif
T = getint();
while (T--) Solve(),Clear();
return 0;
}