树hash
判断树的同构,采用树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的更多相关文章
- 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 ...
- BZOJ_2124_等差子序列_线段树+Hash
BZOJ_2124_等差子序列_线段树+Hash Description 给一个1到N的排列{Ai},询问是否存在1<=p1<p2<p3<p4<p5<…<pL ...
- bzoj2124: 等差子序列线段树+hash
bzoj2124: 等差子序列线段树+hash 链接 https://www.lydsy.com/JudgeOnline/problem.php?id=2124 思路 找大于3的等差数列其实就是找等于 ...
- BZOJ4337:[BJOI2015]树的同构(树hash)
Description 树是一种很常见的数据结构. 我们把N个点,N-1条边的连通无向图称为树. 若将某个点作为根,从根开始遍历,则其它的点都有一个前驱,这个树就成为有根树. 对于两个树T1和T2,如 ...
- 【CSP模拟赛】仔细的检查(树的重心&树hash)
题目描述 nodgd家里种了一棵树,有一天nodgd比较无聊,就把这棵树画在了一张纸上.另一天nodgd更无聊,就又画了一张. 这时nodgd发现,两次画的顺序是不一样的,这就导致了原本的某一个节点 ...
- 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 ...
- 【HDU6647】Bracket Sequences on Tree(树Hash 树上Dp)
题目链接 大意 给出一颗树,按下列方式生成一个括号序列. function dfs(int cur, int parent): print('(') for all nxt that cur is a ...
- BZOJ 4337: BJOI2015 树的同构 树hash
4337: BJOI2015 树的同构 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=4337 Description 树是一种很常见的数 ...
- sort 树 hash 排序
STL 中 sort 函数用法简介 做 ACM 题的时候,排序是一种经常要用到的操作.如果每次都自己写个冒泡之类的 O(n^2) 排序,不但程序容易超时,而且浪费宝贵的比赛时间,还很有可能写错. ST ...
随机推荐
- ReadyAPI 教程和示例(一)
原文:ReadyAPI 教程和示例(一) 声明:如果你想转载,请标明本篇博客的链接,请多多尊重原创,谢谢! 本篇使用的 ReadyAPI版本是2.5.0 通过下图你可以快速浏览一下主要的ReadyAP ...
- Linux+QT4+我忙活半宿的结果
一个简单的计算器,虽然很弱智,而且还不完善,但是通过它,我大致了解了一下QT的用法 QT真的很高级,已经近乎纯面向对象的了. QString可以自己转化成多种类型,就这一点,就已经和C#差不多 ...
- MFC入门--显示静态图片及调用本地软件
MFC是微软开发的基础类库,主要用来开发图形界面应用程序,在学习中,我们要验证算法好坏,一般需要对结果进行可视化. OpenCV是计算机视觉中的开源算法库,集成了很多先进算法,现在想将MFC与Open ...
- Nand Flash 控制器工作原理
对 Nand Flash 存储芯片进行操作, 必须通过 Nand Flash 控制器的专用寄存器才能完成.所以,不能对 Nand Flash 进行总线操作.而 Nand Flash 的写操作也必须块方 ...
- 【默默努力】h5-game-blockBreaker
先放下游戏的效果,我不太会玩游戏 然后放下无私开源的作者大大的地址:https://github.com/yangyunhe369/h5-game-blockBreaker 这个游戏的话,我觉得应该是 ...
- Java虚拟机性能管理神器 - VisualVM(7) 排查JAVA应用程序线程泄漏【转】
Java虚拟机性能管理神器 - VisualVM(7) 排查JAVA应用程序线程泄漏[转] 标签: javajvm线程泄漏 2015-03-11 19:47 1098人阅读 评论(0) 收藏 举报 ...
- JUC 一 Callable
java.util.concurrent.Callable是一个泛型接口,只有一个call()方法 Callable和Runnable的区别 Callable使用call()方法,Runnable使用 ...
- UOJ450 复读机
题意:n个位置,k种颜色.求有多少种方案使得每种颜色恰出现d的倍数次. 解:d=1就快速幂,n,k很小就DP,记得乘组合数来分配位置. d = 2 / 3的时候,考虑生成函数. f(x) = ∑[d ...
- SG函数博弈——poj2311
关于SG函数的博弈 首先定义必败态 x : SG[x]=0 设任意一个状态y,到所有y能到达的状态连一条边,令这些后继为z y : SG[y]=mex(SG[z]) SG[y]==0 : y就是必败态 ...
- C++ Builder 2007中应用数据库SQLite(转载)
第一次使用SQLite数据库,而且BCB2007也不熟,这两者的结合那就更让我难受了.今天只是简单的在BCB中调用SQLite,就花了我一下午时间,这也足见本人知识的浅薄,另一方面也说明我对这二者确实 ...