(笔记)哈希 树哈希
哈希
basic
将字符串转换为模意义下的哈希编码的方法。
具体地,给每个字母赋予一个权值,再当成\(base\)进制处理。主要用途是判断两种状态是否等价。
例:\(abba\)中令\(a\)为\(0\),\(b\)为\(1\),则\(hash(babba)=1\times base^4 +0\times base^3+1\times base^2+1\times base^1+0\times base^0\)
树哈希
构造一个哈希函数\(f(x)\)使得对于以\(x\)为根节点的子树,有根树本质相同时哈希值也相同,即儿子的顺序与哈希值无关。
考虑到如上限制,不难想到用满足交换律的运算构造。
一般地,可以有\(f(x)=\sum _{v\in subtree(x)} f(v)\)或\(f(x)=\prod _{v\in subtree(x)} f(v)\)。
考虑到冲突可能性较大,可优化为\(f(x)=p1+p2^{soncnt(x)}\prod _{v\in subtree(x)} f(v)\)等不同形式。
例题:P5043 【模板】树同构([BJOI2015]树的同构)
代码贴贴:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL MOD=998244353,p1=1331,p2=2333;
const int N=55,INF=1e9;
int n,m;
vector<int>G[N][N];
LL fac[N];
map<LL,int>mp;
LL hs[N];
LL siz[N],son[N];
inline LL tms(LL x,LL y){
return (x%MOD)*(y%MOD)%MOD;
}
inline LL pls(LL x,LL y){
return ((x%MOD)+(y%MOD))%MOD;
}
int rt1,rt2;
int rt;
LL mx[N];
void fr(int u,int fa,int id){
siz[u]=1;
mx[u]=0;
for(int v:G[id][u]){
if(v==fa)continue;
fr(v,u,id);
siz[u]+=siz[v];
mx[u]=max(siz[v],mx[u]);
}
mx[u]=max(mx[u],n-siz[u]);
if(mx[rt1]>mx[u])rt2=rt1,rt1=u;
else if(mx[rt2]>mx[u])rt2=u;
}
LL dfs(int u,int fa,int id){
siz[u]=1;
LL ct=1;
son[u]=0;
for(int v:G[id][u]){
if(v==fa)continue;
son[u]++;
ct=tms(ct,dfs(v,u,id));
siz[u]+=siz[v];
}
ct=tms(ct,fac[son[u]]);
ct=pls(ct,p1);
return ct;
}
LL mk(int id){
return dfs(rt,0,id);
}
LL hs1,hs2;
void init(int id){
mx[0]=INF;
rt1=rt2=0;
fr(rt,0,id);
rt=rt1;
hs1=mk(id);
rt=rt2;
mk(id);
hs2=mk(id);
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>m;
fac[0]=1;
for(int i=1;i<=50;i++){
fac[i]=tms(fac[i-1],p2);
}
for(int i=1;i<=m;i++){
cin>>n;
for(int v=1;v<=n;v++){
int fa;
cin>>fa;
if(!fa){rt=v;continue;}
G[i][fa].push_back(v);
G[i][v].push_back(fa);
}
init(i);
if(mp[hs1]&&mp[hs2]){
mp[hs1]=min(mp[hs1],mp[hs2]);
mp[hs2]=mp[hs1];
cout<<mp[hs1]<<'\n';
}
else if(mp[hs1]){
cout<<mp[hs1]<<'\n';
}
else if(mp[hs2]){
cout<<mp[hs2]<<'\n';
}
else {
mp[hs1]=mp[hs2]=i;
cout<<mp[hs1]<<'\n';
}
}
return 0;
}
线段树 + 哈希
本题主要考察的是转换思想,注意到只需要三项就可以构成基本等差数列,考虑枚举中间项,则左右两项需要关于中间项在数值上对称即可。
通过这个性质可以在值域上建一个桶,每次按顺序加入一个数后对半折看是否有重合位置不相等的地方,可以用线段树+哈希维护。

浙公网安备 33010602011771号