判断树的同构,采用树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. 腾讯bugly接入插件(CocosCreator)

    下载: plugin-bugly.zip (1.4 MB) 插件开源地址: https://github.com/tidys/CocosCreatorPlugins/tree/master/packa ...

  2. php断点续传之文件上传与文件下载

    下载: 原理: Http头的 Range.Content-Range()未启用单点登录GerenalRequest URL: http://www.demotest.com/php/fileDownl ...

  3. vue+layui制作列表页

    优点: 1.选用layui国产. 2.layui有一套完整的前端框架,基本哪来就可以用. 3.选用vue去掉了很多页面元素js拼接的繁琐,及不易修改. 4.vue里面还有一些过滤器等,用起来很方便. ...

  4. 【daydayup】weTalk

    先看一下项目效果 这个是我运行的作者的项目的wetalk-server项目,他还有wetalk-client 项目 先放下作者的github项目地址:https://github.com/mangyu ...

  5. 看 《android权威编程指南》 的笔记

    Android 编译工具 确保ant已安装并正常运行,android sdk的tools/和platform-tools目录包含在可执行文件的搜索路径中 切换到项目目录并执行以下命令: android ...

  6. 高效开发 Dubbo?用 Spring Boot 可得劲!

    不仅简化了 Dubbo 基于 xml 配置的方式,也提高了日常开发效率,甚至提升了工作幸福感. 为了节省亲爱的读者您的时间,请根据以下2点提示来阅读本文,以提高您的阅读收获效率哦. 如果您只有简单的 ...

  7. this指针/常函数、常对象

    this指针引入 类中对象的成员变量和成员函数是分开存储的,sizeof(空class) = 1,另外示例中涉及到字节对齐的问题,double本身的字节为8,int为4,由于字节对齐,int也为8,所 ...

  8. Docker这个新软件究竟是用来干嘛的???

    http://dockone.io/article/378 尝试新软件 对开发者而言,每天会催生出的各式各样的新技术都需要尝试,然而开发者却不太可能为他们一一搭建好环境并进行测试.时间非常宝贵,正是得 ...

  9. 大文件传输 分片上传 上传id 分片号 授权给第三方上传

    https://www.zhihu.com/question/39593108 作者:ZeroOne链接:https://www.zhihu.com/question/39593108/answer/ ...

  10. Java-MyBatis-MyBatis3-XML映射文件:参数

    ylbtech-Java-MyBatis-MyBatis3-XML映射文件:参数 1.返回顶部 1. 参数 你之前见到的所有语句中,使用的都是简单参数.实际上参数是 MyBatis 非常强大的元素.对 ...