一道树hash练习题

题意

给两个二叉树,问两个二叉树有多少对点的子树相同
输入给出每个点的左右儿子,左右儿子在判断子树的时候是位置不同的

数据范围

1 e 5 二叉树点数\le 1e5

解法

树hash模板,由于点数较多,所以需要比较强的hash(这次的树hash比上次的强非常多)

由于是二叉树,所以可以设置多个hash步长,一个给左儿子,一个给右儿子,然后还可以记录子树高度,计算左儿子hash的贡献时平方.总之怎么强怎么来.就可以通过了.(其实这个可以用多hash解决)

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
typedef unsigned long long ull;
const ull step1=233,step2=127;
inline int read(){
	char c=getchar();int t=0,f=1;
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){t=(t<<3)+(t<<1)+(c^48);c=getchar();}
	return t*f;
}
map<ull,long long> mp;
struct tree{
	int n,ch[maxn][2],rt,ton[maxn],dep[maxn];
	ull ha[maxn];
	void dfs(int u){
		if(ch[u][0]!=-1)dfs(ch[u][0]);
		if(ch[u][1]!=-1)dfs(ch[u][1]);
		if(ch[u][0]!=-1)dep[u]=dep[ch[u][0]]+1;
		if(ch[u][1]!=-1)dep[u]=max(dep[u],dep[ch[u][1]])+1;
		if(dep[u]==0)dep[u]=1;
		ha[u]=dep[u];
		if(ch[u][0]!=-1)ha[u]=ha[u]+step1*ha[ch[u][0]]*ha[ch[u][0]];
		if(ch[u][1]!=-1)ha[u]=ha[u]+step2*ha[ch[u][1]];
	}
	void solve(){
		for(int i=1;i<=n;i++)mp[ha[i]]++;
	}
}t1,t2;
int main(){
	t1.n=read(),t2.n=read();
	for(int i=1;i<=t1.n;i++){
		t1.ch[i][0]=read();t1.ch[i][1]=read();
		if(t1.ch[i][0]!=-1)t1.ton[t1.ch[i][0]]=1;
		if(t1.ch[i][1]!=-1)t1.ton[t1.ch[i][1]]=1;
	}
	for(int i=1;i<=t2.n;i++){
		t2.ch[i][0]=read();t2.ch[i][1]=read();
		if(t2.ch[i][0]!=-1)t2.ton[t2.ch[i][0]]=1;
		if(t2.ch[i][1]!=-1)t2.ton[t2.ch[i][1]]=1;
	}
	for(int i=1;i<=t1.n;i++){
		if(!t1.ton[i]){t1.rt=i;break;}
	}
	for(int i=1;i<=t2.n;i++){
		if(!t2.ton[i]){t2.rt=i;break;}
	}
	t1.dfs(t1.rt);t2.dfs(t2.rt);
	t1.solve();
	long long ans=0;
	for(int i=1;i<=t2.n;i++){
		ans=ans+mp[t2.ha[i]];
	}
	printf("%lld\n",ans);
	return 0;
}

发布了62 篇原创文章 · 获赞 1 · 访问量 988

猜你喜欢

转载自blog.csdn.net/wmhtxdy/article/details/103872476