树哈希 学习笔记
一种难卡的 Hash:
对于有根树,某点哈希值 \(h(x) \equiv \text{Const}+\large \sum \limits_{i \in \text{son}(x)} \normalsize f(h(i))\pmod {\text{Const}}\),其中 \(f\) 越随性越好。当 \(f\) 为多项式时,最好进行微扰:\(f_1(x)=f(\lfloor x \cdot 2^{-32} \rfloor) + f(x \ \text{xor} \ \text{Const})\)。此时模数可取 \(2^{64}\)。
选用 \(f(x)=\Theta(x^3)\),测试表明,树的规模为 \(\left\vert V \right\vert = 10^6\) 时,模数在大约 \(2^{64} \approx 10^{19}\) 不会出问题,而取 \(241400290511 \approx 10^{11}\) 就有大问题。说不定是 UOJ 数据太 duliu 了。
UOJ #763 参考代码:
#include <iostream>
#include <set>
#include <utility>
#include <map>
#include <vector>
#define UP(i,s,e) for(auto i=s; i<e; ++i)
using std::cin; using std::cout;
using ull = unsigned long long;
constexpr int N = 1e6;
namespace m{ // }{{{
int in, im, ans[N];
std::vector<int> tos[N];
std::set<ull> mp;
int siz[N];
ull h(ull x){
return (x*x*x*0xFe203+0x3834941CCF);
}
ull f(ull x){
return h(x>>32) + h((unsigned)x^233);
}
ull hash(int x, int fa){
ull now = 1;
for(int i:tos[x]){
if(i == fa) continue;
ull hs = hash(i, x);
mp.insert(hs);
now += f(hs);
}
return now;
}
void work(){
cin >> in;
UP(i, 1, in){
int a, b;
cin >> a >> b; a--, b--;
tos[a].push_back(b); tos[b].push_back(a);
}
mp.insert(hash(0, 0));
cout << mp.size() << '\n';
}
} // {}}}
int main(){ m::work(); return 0; }