洛谷 – P5043 【模板】树同构([BJOI2015]树的同构)(树上哈希)

洛谷 – P5043 【模板】树同构([BJOI2015]树的同构)(树上哈希)题目链接:点击查看题目大意:给出m棵树,对于第i棵树而言,找到1~i中与当前树同构的最小id题目分析:判断有向树同构,可以预处理出质数数组p,然后树形dp,设u为当前节点,v为子节点,那么dp[u]+=dp[v]*p[sz[v]],dp数组设置为unsignedlonglong,让他自然溢出即可,而无根树判断同构,只需要以无根树的重心为根节点,再进行上面有向树判断同构的过程即可,因为每棵树的重心至多有两个,所以都要一起保存下来最

题目链接:点击查看

题目大意:给出 m 棵树,对于第 i 棵树而言,找到 1 ~ i 中与当前树同构的最小 id

题目分析:判断有向树同构,可以预处理出质数数组 p ,然后树形 dp ,设 u 为当前节点,v 为子节点,那么 dp[ u ] += dp[ v ] * p[ sz[ v ] ] ,dp 数组设置为 unsigned long long,让他自然溢出即可,而无根树判断同构,只需要以无根树的重心为根节点,再进行上面有向树判断同构的过程即可,因为每棵树的重心至多有两个,所以都要一起保存下来

最后提一句和 zx 学长闲聊时提到的,我问为什么他的代码要让 p 数组随机打乱一下,zx 学长说有题目可能会卡树上哈希,也就是会卡连续的质数,所以打乱一下基本上就构造不出可以卡掉的数据了

代码:
 

#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#include<unordered_map>
using namespace std;

typedef long long LL;

typedef unsigned long long ull;

const int inf=0x3f3f3f3f;

const int N=60;

int p[]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229};

vector<int>node[N];

vector<ull>Hash[N];

ull f[N];

int rt1,rt2,sz[N],wt[N],n;

void get_root(int u,int fa)
{
	sz[u]=1;
	wt[u]=0;
	for(auto v:node[u])
	{
		if(v==fa)
			continue;
		get_root(v,u);
		sz[u]+=sz[v];
		wt[u]=max(wt[u],sz[v]);
	}
	wt[u]=max(wt[u],n-sz[u]);
	if(rt1==0||wt[rt1]>wt[u])
		rt1=u,rt2=0;
	else if(wt[rt1]==wt[u])
		rt2=u;
}

void dfs(int u,int fa)
{
	f[u]=sz[u]=1;
	for(auto v:node[u])
	{
		if(v==fa)
			continue;
		dfs(v,u);
		f[u]+=f[v]*p[sz[v]];
		sz[u]+=sz[v];
	}
}

void init(int n)
{
	rt1=rt2=0;
	for(int i=1;i<=n;i++)
		node[i].clear();
}

int main()
{
#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);
	random_shuffle(p+1,p+1+50);
	int m;
	scanf("%d",&m);
	for(int i=1;i<=m;i++)
	{
		scanf("%d",&n);
		init(n);
		for(int j=1;j<=n;j++)
		{
			int fa;
			scanf("%d",&fa);
			if(fa)
			{
				node[fa].push_back(j);
				node[j].push_back(fa);
			}
		}
		get_root(1,-1);
		if(rt1)
		{
			dfs(rt1,-1);
			Hash[i].push_back(f[rt1]);
		}
		if(rt2)
		{
			dfs(rt2,-1);
			Hash[i].push_back(f[rt2]);
		}
		if(Hash[i].size()==1)//填个0 
			Hash[i].push_back(0);
		if(Hash[i][0]>Hash[i][1])//排序 
			swap(Hash[i][0],Hash[i][1]);
	}
	for(int i=1;i<=m;i++)
		for(int j=1;j<=i;j++)
			if(Hash[i][0]==Hash[j][0]&&Hash[i][1]==Hash[j][1])
			{
				printf("%d\n",j);
				break;
			}


















   return 0;
}

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/35508.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注