We are given a rooted tree of n vertices. The vertices are to be labeled with numbers 1, 2,..., n so that each label is unique and the heap condition holds, i.e. the label of any vertex is less than the label of its parent. How many such labellings exist? Since this number may be quite large, calculate only its remainder modulo m.
Input
The input contains several tree descriptions. The first line contains the number of input trees t (t250). Each tree description begins with a line containing the size of the tree n (1
n
500000) and an integer m (2
m
109). n - 1 lines follow, i-th of which contains p(i + 1), the number of the parent of the i + 1-th vertex (1
p(i + 1)
i). Vertex number 1 will be the root in each tree, so its parent will not be given. Total size of the input will not exceed 50MB.
Output
For each tree output the number of its valid labellings modulo given m.
Explanation for sample:The 8 possible labellings from the last example test case are as follows:
![\epsfbox{p4390.eps}](http://uva.onlinejudge.org/external/14/p4390.png)
Sample Input
4 3 1000000 1 1 4 1000000 1 1 1 5 1000000 1 2 3 4 5 1000000 1 1 3 3
Sample Output
2 6 1 8
给了树的形状,节点编号1-N,父节点小于子节点,这样的树有多少个。
跟训练指南上面那个村民排队(不能排在父亲前面)是一样的。根是i,假设每个子树有f(ci)中排法,每个子树有s(ci)个节点,先把每个子树中的元素看成一样的,就有(s(i)-1)!/(s(c1)*s(c2)...*s(ck)),再乘上每种子树的排法,也就是f(i)=f(c1)*f(c2)..*f(ck)*(s(i)-1)!/(s(c1)*s(c2)...*s(ck))。再把子树的f展开,注意到所有非根节点u以(s(u)-1)!在分子出现一次,以s(u)!在分母出现一次,最后化简完答案就是f(root)=(s(root)-1)!/(s(1)*s(2)..s(n)),因为s(root)=n+1,所以f(root)=n!/(s(1)*s(2)..s(n)),一般类似的问题都可以这么做。
那么只需要统计出每个子树的节点个数就行了,递归应该会爆栈,用队列比较好。
还有一个难点是取余,解决的办法是把分子分母都换成质数的幂的形式,在分子上幂是正的,分母上是负的,由于最后答案肯定是正整数,所以每个因子的系数肯定不会小于0的。快速幂就OK。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cstdlib>
#include<cmath>
#define INF 0x3f3f3f3f
#define MAXN 500010
#define MAXM 50010
#define MAXNODE 4*MAXN
#define MOD 1000000000
#define eps 1e-9
using namespace std;
int T,P,N,M,isprime[MAXN],prime[MAXM],coef[MAXM],cnt[MAXN],isleaf[MAXN],fa[MAXN];
queue<int> q;
void prime_table(){
P=0;
isprime[1]=0;
for(int i=2;i<MAXN;i++) isprime[i]=1;
for(int i=2;i<MAXN;i++){
if(isprime[i]){
isprime[i]=P;
prime[P++]=i;
}
for(int j=i+i;j<MAXN;j+=i) isprime[j]=0;
}
}
void init(){
memset(isleaf,0,sizeof(isleaf));
memset(fa,-1,sizeof(fa));
scanf("%d%d",&N,&M);
for(int i=1;i<=N;i++) cnt[i]=1;
for(int i=2;i<=N;i++){
scanf("%d",&fa[i]);
isleaf[fa[i]]++;
}
while(!q.empty()) q.pop();
for(int i=1;i<=N;i++) if(!isleaf[i]) q.push(i);
while(!q.empty()){
int u=q.front();
q.pop();
if(u==1) continue;
cnt[fa[u]]+=cnt[u];
isleaf[fa[u]]--;
if(!isleaf[fa[u]]) q.push(fa[u]);
}
}
long long bigpow(int x,int n,int M){
long long ret=1,t=x%M;
while(n){
if(n&1) ret=ret*t%M;
t=t*t%M;
n>>=1;
}
return ret;
}
void fac(int x,int v){
for(int i=0;prime[i]<=x;i++){
if(x==1) return;
while(x%prime[i]==0){
coef[i]+=v;
x/=prime[i];
}
//不加下面这个直接超时
if(isprime[x]){
coef[isprime[x]]+=v;
return;
}
}
}
long long solve(){
memset(coef,0,sizeof(coef));
for(int i=2;i<N;i++) fac(i,1);
for(int i=2;i<=N;i++) fac(cnt[i],-1);
long long ret=1;
for(int i=0;i<P;i++) if(coef[i]) ret=ret*bigpow(prime[i],coef[i],M)%M;
return ret;
}
int main(){
freopen("in.txt", "r", stdin);
prime_table();
scanf("%d",&T);
while(T--){
init();
printf("%lld\n",solve());
}
return 0;
}