https://acm.bnu.edu.cn/v3/statments/jag2016.pdf
题意:
num(T1,d) 为树T1在深度为d这一层的子节点数量
定义 两棵树相似 的条件为
对所有的d, S(T,d) equals S(T ′ ,d)
从叶子节点开始bfs,每个节点的相似度信息可以hash成一个数。
从当前节点开始去更新父亲节点的相似度信息
只有当一个节点的所有儿子都访问完了(也即得到了自身完整的相似度信息),才进入队列
在每一层计算一次,具有相同相似度的节点对答案的贡献为 C(X,2)
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <queue>
#include <map>
#include <set>
#include <vector>
using namespace std;
const int N=100005;
typedef long long ll;
vector<int >mp[N];
int son_num[N];
int son_come[N];
unsigned long long hash_val[N];
int fa[N];
void dfs(int x,int f)
{
for (int i=0; i<mp[x].size(); i++)
{
int v=mp[x][i];
if (v==f)continue;
fa[v]=x;
son_num[x]++;
dfs(v,x);
}
}
map<unsigned long long ,int> vis;
map<unsigned long long ,int> ::iterator it;
struct node
{
int dep,x;
node() {}
node(int a,int b)
{
x=a,dep=b;
}
};
queue<node> q;
int main()
{
int n,u,v;
cin>>n;
for (int i=1; i<n; i++)
{
scanf("%d%d",&u,&v);
mp[u].push_back(v);
mp[v].push_back(u);
}
dfs(1,0);
for (int i=1; i<=n; i++)
if (!son_num[i]) q.push(node(i,1));
ll ans=0;
while(!q.empty())
{
int sz=q.size();
vis.clear();
for (int i=1; i<=sz; i++)
{
node tp=q.front();
q.pop();
hash_val[tp.x]+=239;
vis[hash_val[tp.x]]++;
int f=fa[tp.x];
hash_val[f]+=hash_val[tp.x]*239;
son_come[f]++;
if (son_come[f]==son_num[f])
q.push(node(f,tp.dep+1));
}
for (it=vis.begin();it!=vis.end();it++)
ans+= 1LL*it->second*(it->second-1)/2;
}
printf("%lld\n",ans);
return 0;
}