树哈希 学习笔记

一种难卡的 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; }
posted @ 2023-08-07 20:32  383494  阅读(26)  评论(0编辑  收藏  举报