Aizu 2784 Similarity of Subtrees

来源:互联网 发布:mysql 5.7.20安装教程 编辑:程序博客网 时间:2024/05/18 01:16

Problem

judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2784
vjudge.net/problem/Aizu-2784

Meaning

定义S(T,d):以 T 为根的子树中,深度为 d 的结点个数(根的深度为 0)。
给定一棵树,问有多少对(i,j)满足:

  • i < j
  • 对任意非负的 d 都有:S(Ti,d)= S(Tj,d)

Analysis

可以将每一棵子树都 hash 成一个 P 进制的数,然后找 hash 值相同的那些子树更新答案。
设子树 T 有深都为 1、2、…、m 的后代结点,nd 表示 T 树中深度为 d 的后代结点个数,则(其中一种) hash 公式为:
Hash(T)= (n1+n2P+n3P2++nmPm1) % MOD
(相当于用 P 进制数,在位权为 Pi 的位置的数表示子树 T 中深度为 i + 1 的结点个数。P 应当不小于总结点个数(?))

Code

#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int N = 100000;const unsigned long long P = N + 3;int head[N+1], to[N], nxt[N];void add_edge(int f, int t, int sz){    to[sz] = t;    nxt[sz] = head[f];    head[f] = sz;}// 用 unsigned long long 装 hash 值// 相当于 mod 2^63 - 1unsigned long long h[N+1]; // hashint son[N+1];void dfs(int now){    son[now] = h[now] = 0;    for(int i = head[now]; ~i; i = nxt[i])    {        ++son[now];        dfs(to[i]);        h[now] += h[to[i]] * P;    }    h[now] += son[now];}int main(){    int n;    scanf("%d", &n);    memset(head, -1, sizeof head);    for(int i = 1, f, t, sz = 0; i < n; ++i)    {        scanf("%d%d", &f, &t);        add_edge(f, t, sz++);    }    dfs(1);    sort(h + 1, h + n + 1);    long long ans = 0;    for(int i = 1, j; i <= n; i = j)    {        for(j = i; j <= n && h[j] == h[i]; )            ++j;        ans += (long long)(j - i) * (j - i - 1) >> 1;    }    printf("%lld\n", ans);    return 0;}
原创粉丝点击