【problem description】
首先引入lca(x, y)这个记号,表示x和y两个节点在树上的最近公共祖先。然后Aponoia定义了“不三不四树”。假设在一棵有根树上存在五个互不相同的节点,分别记为a, b, c, d, z,若这5个点同时满足以下要求:a, b, c, d, lca(a, b),lca(c, d),lca(lca(a, b),lca(c, d))这7个节点互不相同,并且z是lca(lca(a, b), lca(c, d))的祖先;那么五元组(a, b, c, d, z)表示了一棵合法的“不三不四树”。同时,交换a, b, c, d, z的顺序只算一种。
现在给定一棵以1号节点为根的树,请你求出满足上述要求的“不三不四树”的总数。由于答案可能很大,请输出答案mod 1234567891后的结果。
【input format】
第一行一个正整数,表示树的节点数。
第二到n行每行两个正整数x, y(x < y),表示节点x是节点y的父节点。
【output format】
一行一个整数,表示“不三不四树”的种数mod 1234567891后的结果。
【sample input】
10
1 2
2 3
3 4
3 5
4 6
4 7
4 8
5 9
5 10
【sample output】
6
【data scale】
对于20%的数据,1 <= n <= 15。
对于50%的数据,1 <= n <= 5000。
对于另外10%的数据,保证树的高度为4.
对于另外20%的数据,保证树的高度为5.
对于100%的数据,1 <= n <= 500000。
【analysis】
此题中虽说lca,这个其实是个干扰。
这题实际上是个树形dp。
有题目中可以知道,不三不四树一定是深度为4。
算出每个点作为根时所得的树的数量,最后应用前缀和思想,将其统一到根节点,即可。
注意由于数据太大,需要用long long。
【accepted】
#include<bits/stdc++.h>
using namespace std;
#define mo 1234567891
long long n;
vector<long long >son[510000];
long long dp[510000][11];
void readp(){
cin>>n;
for(int i=1;i<n;i++){
int x,y;
cin>>x>>y;
son[x].push_back(y);
}
}
void dfs(long long k){
long long tot=0,tott=0;
dp[k][4]=1;
for(int i=0;i<son[k].size();i++){
dfs(son[k][i]);
for(int j=1;j<=4;j++){
dp[k][j]+=dp[son[k][i]][j];
dp[k][j]%=mo;
}
dp[k][1]+=dp[son[k][i]][2];
dp[k][1]%=mo;
dp[k][2]+=dp[son[k][i]][3]*tot;
tot+=dp[son[k][i]][3];dp[k][2]%=mo;
dp[k][3]+=dp[son[k][i]][4]*tott;
tott+=dp[son[k][i]][4];dp[k][3]%=mo;
}
return ;
}
void work(){
dfs(1);
cout<<dp[1][1]<<endl;
}
int main(){
freopen("threefour.in","r",stdin);
freopen("threefour.out","w",stdout);
readp();
work();
return 0;
}