码迷,mamicode.com
首页 > 其他好文 > 详细

P5043 【模板】树同构([BJOI2015]树的同构) |树哈希

时间:2020-04-16 15:08:13      阅读:72      评论:0      收藏:0      [点我收藏+]

标签:cstring   span   输入格式   namespace   names   turn   bre   lin   set   

题目描述

树是一种很常见的数据结构。

我们把 \(N\) 个点,\(N-1\) 条边的连通无向图称为树。

若将某个点作为根,从根开始遍历,则其它的点都有一个前驱,这个树就成为有根树。

对于两个树 \(T_1\)\(T_2\),如果能够把树 \(T_1\)? 的所有点重新标号,使得树 \(T_1\)? 和树 \(T_2\) 完全相同,那么这两个树是同构的。也就是说,它们具有相同的形态。

现在,给你 \(M\) 个有根树,请你把它们按同构关系分成若干个等价类。

输入格式

第一行,一个整数 \(M\)

接下来 \(M\) 行,每行包含若干个整数,表示一个树。第一个整数 \(N\)表示点数。接下来 \(N\) 个整数,依次表示编号为 \(1\)\(N\) 的每个点的父亲结点的编号。根节点父亲结点编号为 \(0\)

输出格式

输出 \(M\) 行,每行一个整数,表示与每个树同构的树的最小编号。


好东西,好东西

#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define int long long
inline int read(){
    int x=0,f=1; char ch=getchar();
    while(!isdigit(ch)) {if(ch==‘-‘)f=-1;ch=getchar();}
    while(isdigit(ch)) {x=x*10+ch-48;ch=getchar();}
    return x*f;
}
const int N=60,M=2*N,mod=998244353;
int nxt[M],head[N],go[M],tot;
inline void add(int u,int v){
	nxt[++tot]=head[u],head[u]=tot,go[tot]=v;
}
int p[1000010],top,siz[N],h[N],g[N],fr[N],turn;
bool vis[1000010];
vector<int>v[N];
inline void getp(int n){
	for(int i=2;i<=n;i++){
		if(!vis[i])p[++top]=i;
		for(int j=1;j<=top&&i*p[j]<=n;j++){
			vis[i*p[j]]=1;
			if(i%p[j]==0)break;
		}
	}
}
int n;
void DFS_1(int x,int fa){
	h[x]=siz[x]=1;
	for(int i=head[x];i;i=nxt[i]){
		int v=go[i];
		if(v==fa)continue;
		DFS_1(v,x);
		h[x]=(h[x]+h[v]*p[siz[v]]%mod)%mod;
		siz[x]+=siz[v];
	}
}
void DFS_2(int x,int fa,int V){
	g[x]=(h[x]+V*p[n-siz[x]]%mod)%mod;
	v[turn].push_back(g[x]);
	V=(V*p[n-siz[x]]%mod+1)%mod;
	for(int i=head[x];i;i=nxt[i]){
		int v=go[i];
		if(v==fa)continue;
		DFS_2(v,x,(V+h[x]-1-h[v]*p[siz[v]]%mod+mod)%mod);
	}
}
inline bool equal(int a,int b){
	int len=v[a].size();
	if(len!=v[b].size())return 0;
	for(int i=0;i<len;i++)if(v[a][i]!=v[b][i])return 0;
	return 1;
}
signed main(){
	getp(1000009);
	int m; cin>>m;
	for(turn=1;turn<=m;turn++){
		n=read(); tot=0;
		memset(head,0,sizeof(head));
		memset(nxt,0,sizeof(nxt));
		for(int i=1,x;i<=n;i++){
			x=read();
			if(x==0)continue;
			add(i,x),add(x,i);
		}
		DFS_1(1,0);
		DFS_2(1,0,0);
		sort(v[turn].begin(),v[turn].end());
	}
	for(int i=1;i<=m;i++)fr[i]=i;
	for(int i=2;i<=m;i++)
	for(int j=1;j<i;j++){
		if(equal(i,j)){
			fr[i]=fr[j];
			break;
		}
	}
	for(int i=1;i<=m;i++)
	printf("%d\n",fr[i]);
}

P5043 【模板】树同构([BJOI2015]树的同构) |树哈希

标签:cstring   span   输入格式   namespace   names   turn   bre   lin   set   

原文地址:https://www.cnblogs.com/naruto-mzx/p/12712792.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!