【模板】树哈希

https://peehs-moorhsum.blog.uoj.ac/blog/7891

题目描述

对一棵树求 hash 值,以判断两棵树是否同构。有有根树和无根树两个版本。

solution

找一个随机函数 f(可以选 xor-shift),然后每个点的子树的哈希值如下计算:

hu=1+vf(hv)

这是有根树的情况,对于无根树,1. 可以换根 dp 求出以任意点为根的 hash 值,然后取最小的;2. 找重心,求出重心为根的 hash 值,有两个重心取 hash 值较小的。

code

P5043 【模板】树同构([BJOI2015]树的同构)

#include <bits/stdc++.h>
using namespace std;
#ifdef LOCAL
#define debug(...) fprintf(stderr, ##__VA_ARGS__)
#else
#define debug(...) void(0)
#endif
typedef long long LL;
using word = unsigned long long;
mt19937_64 rng{random_device{}()};
const word mask = rng();
word shift(word x) {
  x ^= mask;
  x ^= x << 13;
  x ^= x >> 7;
  x ^= x << 17;
  return x ^ mask;
}
int n, m;
basic_string<int> g[1000010];
word f[1000010], hsh[1000010];
word dfs(int u, int fa) {
  word &ans = f[u] = 1;
  for (int v : g[u]) if (v != fa) ans += shift(dfs(v, u));
  return ans;
}
void dfs2(int u, int fa) {
  for (int v : g[u]) if (v != fa) f[v] += shift(f[u] - shift(f[v])), dfs2(v, u);
}
int main() {
#ifndef LOCAL
  cin.tie(nullptr)->sync_with_stdio(false);  
#endif
  cin >> m;
  map<word, int> mp;
  for (int t = 1; t <= m; t++) {
    cin >> n;
    for (int i = 1; i <= n; i++) g[i].clear();
    for (int i = 1, x; i <= n; i++) {
      cin >> x;
      if (x) g[i] += x, g[x] += i;
    }
    dfs(1, 0);
    dfs2(1, 0);
    hsh[t] = *min_element(f + 1, f + n + 1);
    if (!mp.count(hsh[t])) mp[hsh[t]] = t;
  }
  for (int i = 1; i <= m; i++) cout << mp[hsh[i]] << endl;
  return 0;
}
posted @   caijianhong  阅读(24)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
历史上的今天:
2023-10-09 题解 accoders::NOI 5515【Precise】
点击右上角即可分享
微信分享提示