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


    题目描述

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

    我们把 (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
    ",fr[i]);
    }
    
  • 相关阅读:
    KMP
    KMP 算法详解
    快慢指针-链表环入口问题
    算法题——只出现一次的数字
    DECODE 与CASE WHEN 的比较
    Mybatis动态传入tableName--非预编译(STATEMENT)
    mysql数据库出现无法登录(ERROR 1045 ),预防和解决及系列问题解决方法。
    15.linux iptables防火墙规则vsftp服务
    14.LAMP服务 Linux Apache Mysql Php和防护机制 xinetd、tcp wapper
    13.mysql数据库
  • 原文地址:https://www.cnblogs.com/naruto-mzx/p/12712792.html
Copyright © 2020-2023  润新知