树hash

Posted segmenttree

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树hash相关的知识,希望对你有一定的参考价值。

神仙的博客(我就是用的这种方法)

树hash的方法很多,我用的是上面博客里面的方法

最近跟Wendigo神仙做题目,发现自己思维不行

题目

BJOI2015树的同构

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int mod=998244341;
const int N=100000;
const int M=1299720;
struct edge
{
	int to,nxt;
}e[N*2];
int h[N],E=0;
ll f[N+5],g[N+5],siz[N];
int p[N+5],tot=0;
bitset<M+5> used;
vector<int> hs[N];
int n,m;
int vis[N];
void addedge(int u,int v)
{
	E++;
	e[E].to=v,e[E].nxt=h[u];
	h[u]=E;
	return;
}
void getsieve(int n)
{
	used[0]=used[1]=1;
	tot=0;
	for(int i=2;i<=n;i++)
	{
		if(!used[i]) p[++tot]=i;
		for(int j=1;j<=tot&&p[j]*i<=n;j++)
		{
			used[p[j]*i]=1;
			if(i%p[j]==0) break;
		}
	}
	return;
}
void dfs(int u,int fa)
{
	f[u]=1;
	siz[u]=1;
	for(int i=h[u];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(v==fa) continue;
		dfs(v,u);
		siz[u]+=siz[v];
		f[u]+=f[v]*p[siz[v]]%mod;
		f[u]%=mod;
	}
	return;
}
void dfs1(int u,int fa)
{
	g[u]=0;
	if(u!=1)
	{
		g[u]=(f[fa]-p[siz[u]]*f[u]%mod+mod)%mod;
		g[u]=(g[u]+g[fa]*p[n-siz[fa]]%mod)%mod;		
	}
	for(int i=h[u];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(v==fa) continue;
		dfs1(v,u);
	}
	return;
}
int cmp(vector<int> &a,vector<int> &b)
{
	int la=a.size(),lb=b.size();
	if(la!=lb) return 0;
	for(int i=0;i<la;i++) if(a[i]!=b[i]) return 0;
	return 1;
}
void insert(int tot)
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++) h[i]=0;
	E=0;
	int fa;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&fa);
		if(!fa) continue;
		addedge(i,fa);
		addedge(fa,i);
	}
	dfs(1,0);
	dfs1(1,0);
	for(int i=1;i<=n;i++) hs[tot].push_back((g[i]*p[n-siz[i]]%mod+f[i])%mod);
	sort(hs[tot].begin(),hs[tot].end());
	return;
}
int main()
{
	getsieve(M);
	scanf("%d",&m);
	for(int i=1;i<=m;i++) insert(i);
	for(int i=1;i<=m;i++) vis[i]=i; 
	for(int i=1;i<=m;i++)	
	{
		for(int j=i+1;j<=m;j++)
		{
			if(cmp(hs[i],hs[j]))
			{
				vis[j]=min(vis[j],i);
			}
		}
	}
	for(int i=1;i<=m;i++) printf("%d
",vis[i]);
	return 0;
}

[JSOI2016]独特的树叶

枚举那个树叶,然后在父亲的hash值减2,然后在map里面找

附一张图

技术图片

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int mod=999999137;
const int N=100000;
const int M=1299720;
struct edge
{
	int to,nxt;
}e[N*2+5];
int h[N+5],E=0;
ll f[N+5],g[N+5],t[N+5],siz[N+5];
int p[N+5],tot=0;
bitset<M+5> used;
map<int,int> c;
int n,deg[N+5],pa[N+5];
int root=0;
void addedge(int u,int v)
{
	E++;
	e[E].to=v,e[E].nxt=h[u];
	h[u]=E;
	return;
}
void getsieve(int n)
{
	used[0]=used[1]=1;
	tot=0;
	for(int i=2;i<=n;i++)
	{
		if(!used[i]) p[++tot]=i;
		for(int j=1;j<=tot&&p[j]*i<=n;j++)
		{
			used[p[j]*i]=1;
			if(i%p[j]==0) break;
		}
	}
	return;
}
void dfs(int u,int fa)
{
	f[u]=1;
	siz[u]=1;
	pa[u]=fa;
	for(int i=h[u];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(v==fa) continue;
		dfs(v,u);
		siz[u]+=siz[v];
		f[u]+=f[v]*p[siz[v]]%mod;
		f[u]%=mod;
	}
	return;
}
void dfs1(int u,int fa)
{
	g[u]=0;
	if(u!=root)
	{
		g[u]=(f[fa]-p[siz[u]]*f[u]%mod+mod)%mod;
		g[u]=(g[u]+g[fa]*p[n-siz[fa]]%mod)%mod;		
	}
	for(int i=h[u];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(v==fa) continue;
		dfs1(v,u);
	}
	return;
}
int main()
{
	getsieve(M);
	scanf("%d",&n);
	int u,v;
	for(int i=1;i<n;i++)
	{
		scanf("%d%d",&u,&v);
		addedge(u,v);
		addedge(v,u);
	}
	root=1;
	dfs(root,0);
	dfs1(root,0);
	for(int i=1;i<=n;i++) 
	{
		c[(f[i]+g[i]*p[n-siz[i]]%mod)%mod]++;
	}
	n++;
	for(int i=1;i<=n;i++) h[i]=0;
	E=0;
	for(int i=1;i<n;i++)
	{
		scanf("%d%d",&u,&v);
		deg[u]++,deg[v]++;
		addedge(u,v);
		addedge(v,u);
	}
	for(int i=1;i<=n;i++) if(deg[i]>1) root=i;
	dfs(root,0);
	dfs1(root,0);
	for(int i=1;i<=n;i++) t[i]=(f[i]+g[i]*p[n-siz[i]]%mod)%mod;
	for(int i=1;i<=n;i++)
	{
		if(deg[i]>1) continue;
		ll has=(t[pa[i]]-2+mod)%mod;
		if(c[has]) return printf("%d
",i),0;
	}
	return 0;
}

以上是关于树hash的主要内容,如果未能解决你的问题,请参考以下文章

trie树查找和hash查找比较(大量数据)

树Hash

HDU 6599 I Love Palindrome String (回文树+hash)

如何理解这段代码片段中的两对括号?

树hash

字符串hash与字典树