判断树的同构,采用树hash的方式。

树hash定义在有根树上。判断无根树同构的时候,可以比较重心为根的hash值或者比较每个点为根的hash值。

h[x]表示x为根的子树的hash,g[x]表示x为根时全树的hash。

我采用的方法是

h[x] = 1 + ∑h[y] * p[siz[y]]

于是g[x] = g[fa] - h[x] * p[siz[x]] + h[x]

例题1: BJOI2015 树的同构

判断无根树同构,我是比较了每个点为根时的hash值。

 #include <bits/stdc++.h>

 typedef long long LL;
const int N = , MO = ; struct Edge {
int nex, v;
}edge[N << ]; int tp; int e[N], n, m, turn, fr[N], p[], top, siz[N], h[N], g[N];
std::vector<int> v[N];
bool vis[]; inline void add(int x, int y) {
tp++;
edge[tp].v = y;
edge[tp].nex = e[x];
e[x] = tp;
return;
} inline bool equal(int a, int b) {
int len = v[a].size();
if(len != v[b].size()) return false;
for(int i = ; i < len; i++) {
if(v[a][i] != v[b][i]) return false;
}
return true;
} inline void getp(int n) {
for(int i = ; i <= n; i++) {
if(!vis[i]) {
p[++top] = i;
}
for(int j = ; j <= top && i * p[j] <= n; j++) {
vis[i * p[j]] = ;
if(i % p[j] == ) {
break;
}
}
}
return;
} void DFS_1(int x, int f) {
siz[x] = ;
h[x] = ;
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(y == f) continue;
DFS_1(y, x);
h[x] = (h[x] + 1ll * h[y] * p[siz[y]] % MO) % MO;
siz[x] += siz[y];
}
return;
} void DFS_2(int x, int f, int V) {
g[x] = (h[x] + 1ll * V * p[n - siz[x]] % MO) % MO;
v[turn].push_back(g[x]);
V = (1ll * V * p[n - siz[x]] % MO + ) % MO;
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(y == f) {
continue;
}
DFS_2(y, x, ((LL)V + h[x] - - 1ll * h[y] * p[siz[y]] % MO + MO) % MO);
}
return;
} int main() {
getp();
scanf("%d", &m);
for(turn = ; turn <= m; turn++) {
scanf("%d", &n);
tp = ;
memset(e + , , n * sizeof(int));
for(int i = , x; i <= n; i++) {
scanf("%d", &x);
if(x) {
add(x, i);
add(i, x);
}
}
DFS_1(, );
DFS_2(, , );
std::sort(v[turn].begin(), v[turn].end());
/*for(int i = 0; i < n; i++) {
printf("%d ", v[turn][i]);
}
puts("\n");*/
} for(int i = ; i <= m; i++) {
fr[i] = i;
}
for(int i = ; i <= m; i++) {
for(int j = ; j < i; j++) {
if(equal(i, j)) {
fr[i] = fr[j];
break;
}
}
}
for(int i = ; i <= m; i++) {
printf("%d\n", fr[i]);
}
return ;
}

AC代码

例题2: JSOI2016 独特的树叶

对第一棵树的所有点为根的hash值建立set,然后枚举第二棵树,在set中查。

 #include <bits/stdc++.h>

 const int N = , MO = ;

 struct Edge {
int nex, v;
}; std::set<int> st;
int p[], top, in[N], near[N];
bool vis[]; inline int qpow(int a, int b) {
int ans = ;
while(b) {
if(b & ) ans = 1ll * ans * a % MO;
a = 1ll * a * a % MO;
b = b >> ;
}
return ans;
} struct Tree {
Edge edge[N << ]; int tp;
int e[N], h[N], g[N], siz[N], n;
inline void init(int t) {
n = t;
tp = ;
memset(e + , , n * sizeof(int));
return;
}
inline void add(int x, int y) {
edge[++tp].v = y;
edge[tp].nex = e[x];
e[x] = tp;
return;
}
void DFS_1(int x, int f) {
siz[x] = ;
h[x] = ;
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(y == f) {
continue;
}
DFS_1(y, x);
siz[x] += siz[y];
h[x] = (h[x] + 1ll * h[y] * p[siz[y]] % MO) % MO;
}
//printf("x = %d h[x] = %d \n", x, h[x]);
return;
}
void DFS_2(int x, int f, int V) {
g[x] = (h[x] + 1ll * V * p[n - siz[x]] % MO) % MO;
//printf("x = %d v = %d g = %d \n", x, V, g[x]);
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(y == f) {
continue;
}
DFS_2(y, x, (g[x] - 1ll * h[y] * p[siz[y]] % MO + MO) % MO);
}
return;
}
}t0, t1; inline void getp(int n) {
for(int i = ; i <= n; i++) {
if(!vis[i]) {
p[++top] = i;
}
for(int j = ; j <= top && i * p[j] <= n; j++) {
vis[i * p[j]] = ;
if(i % p[j] == ) {
break;
}
}
}
return;
} int main() { getp(); int n;
scanf("%d", &n);
t0.init(n);
t1.init(n + );
int x, y;
for(int i = ; i < n; i++) {
scanf("%d%d", &x, &y);
t0.add(x, y);
t0.add(y, x);
}
for(int i = ; i <= n; i++) {
scanf("%d%d", &x, &y);
t1.add(x, y);
t1.add(y, x);
in[x]++;
in[y]++;
near[x] = y;
near[y] = x;
} t0.DFS_1(, );
t0.DFS_2(, , );
for(int i = ; i <= n; i++) {
st.insert(t0.g[i]);
//printf("%d hash = %d \n", i, t0.g[i]);
} t1.DFS_1(, );
t1.DFS_2(, , );
for(int i = ; i <= n + ; i++) {
if(in[i] == ) {
int x = (t1.g[near[i]] - + MO) % MO;
if(st.find(x) != st.end()) {
printf("%d\n", i);
return ;
}
}
} return ;
}

AC代码

更多例题:

树hash的更多相关文章

  1. Codeforces Round #321 (Div. 2) E. Kefa and Watch 线段树hash

    E. Kefa and Watch Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/580/prob ...

  2. BZOJ_2124_等差子序列_线段树+Hash

    BZOJ_2124_等差子序列_线段树+Hash Description 给一个1到N的排列{Ai},询问是否存在1<=p1<p2<p3<p4<p5<…<pL ...

  3. bzoj2124: 等差子序列线段树+hash

    bzoj2124: 等差子序列线段树+hash 链接 https://www.lydsy.com/JudgeOnline/problem.php?id=2124 思路 找大于3的等差数列其实就是找等于 ...

  4. BZOJ4337:[BJOI2015]树的同构(树hash)

    Description 树是一种很常见的数据结构. 我们把N个点,N-1条边的连通无向图称为树. 若将某个点作为根,从根开始遍历,则其它的点都有一个前驱,这个树就成为有根树. 对于两个树T1和T2,如 ...

  5. 【CSP模拟赛】仔细的检查(树的重心&树hash)

    题目描述 nodgd家里种了一棵树,有一天nodgd比较无聊,就把这棵树画在了一张纸上.另一天nodgd更无聊,就又画了一张.  这时nodgd发现,两次画的顺序是不一样的,这就导致了原本的某一个节点 ...

  6. TZOJ 4292 Count the Trees(树hash)

    描述 A binary tree is a tree data structure in which each node has at most two child nodes, usually di ...

  7. 【HDU6647】Bracket Sequences on Tree(树Hash 树上Dp)

    题目链接 大意 给出一颗树,按下列方式生成一个括号序列. function dfs(int cur, int parent): print('(') for all nxt that cur is a ...

  8. BZOJ 4337: BJOI2015 树的同构 树hash

    4337: BJOI2015 树的同构 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=4337 Description 树是一种很常见的数 ...

  9. sort 树 hash 排序

    STL 中 sort 函数用法简介 做 ACM 题的时候,排序是一种经常要用到的操作.如果每次都自己写个冒泡之类的 O(n^2) 排序,不但程序容易超时,而且浪费宝贵的比赛时间,还很有可能写错. ST ...

随机推荐

  1. falcon监控指标

    mysql监控指标: 流量状态: Bytes_received/s #平均每秒从所有客户端接收到的字节数,单位KB Bytes_sent/s #平均每秒发送给所有客户端的字节数,单位KB

  2. leetcode-117-填充每个节点的下一个右侧节点指针②

    ---恢复内容开始--- 题目描述: 方法一:层次遍历 """ # Definition for a Node. class Node: def __init__(sel ...

  3. 集合划分——cf1028D思维题

    非常思维的一道题目,题意很长 给定s1,s2两个集合,s1维护最大值,s2维护最小值,s1的所有元素要比s2小 操作1:往两个集合里的任意一个添加x 操作2:把x从所在的集合里删掉:要求被删的x必须是 ...

  4. springboot与任务(异步任务)

    描述:在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的:但是在处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用多线程来完成此类任务,其实,在Spring 3.x ...

  5. 19-11-12-Aftern-℘

    我饿死了,于是写写博客安慰一下即将退役的自己. ZJ: T1. 三种颜色,想到一道神奇的‘天空龙’. 于是觉得此题可做. 那好了. 于是切掉,还拿了一个暴力对拍.疯狂A. 啊dfs慢的要死了 T2一眼 ...

  6. System.Web.Mvc.PartialViewResult.cs

    ylbtech-System.Web.Mvc.PartialViewResult.cs 1.程序集 System.Web.Mvc, Version=5.2.3.0, Culture=neutral, ...

  7. Spring MVC(十三)--保存并获取属性参数

    这里的属性参数主要是指通过request.session.cookie等设置的属性,有时候我们需要将一些请求的参数保存到HTTP的request或者session对象中去,在控制器中也会进行设置和获取 ...

  8. 03_Sklearn的安装

    1.Scikit-learn库介绍:包含许多知名的机器学习算法的实现,文档完善.容易上手,丰富的API. 2.安装:创建一个基于Python3的虚拟环境(可以在已有的虚拟环境中):mkvirtuale ...

  9. elasticsearch 过滤器的种类

    elasticsearch之查询过滤 elasticsearch elastic-search xixicat 2月13日发布 推荐 1 推荐 收藏 2 收藏,289 浏览 序 本文主要记录es的查询 ...

  10. session中load()跟get()的区别

    1.相同点:Session.load/get方法均可以根据指定的实体类和id从数据库读取记录,并返回与之对应的实体对象. 2.区别在于: (1)如果未能发现符合条件的记录,get方法返回null,而l ...