标签: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