树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 ...
随机推荐
- 论文阅读笔记---HetConv
1 写在前边的话 HetConv性能:当使用HetConv取代标准卷积之后,FLOPs大概是之前的1/8到1/3,更重要的是精度几乎不变!!! 论文地址:https://arxiv.org/abs/1 ...
- java_Properties集合
package propertiesTest; import java.io.FileReader; import java.io.FileWriter; import java.io.IOExcep ...
- 基于windows消息的响应USB插入或取出
导语:当有设备进入windows时,系统会向所有的应用层发送WM_DEVICECHANGE消息.进一步根据相应的事件判断设备. LRESULT CALLBACK WndProc(HWND hWnd, ...
- Atcoder arc096
C:Half and Half 几个if语句贪心算一算就好了 #include<cstdio> #include<algorithm> using namespace std; ...
- 关于set_multicycle_path的最后总结
(1) –start/-end决定移动的距离以start_clock/end_clock为单元: (2) 对于-setup选项,移动距离是在默认关系的基础上移动(数值-1): (3) 默认往后, se ...
- [JZOJ4649] 【NOIP2016提高A组模拟7.17】项链
题目 描述 题目大意 给你一堆小串,每个小串都有一定的分数. 让你构造一个字符串,若子串中出现了之前的小串,就可以得到对应的分数(可以重复) 问最大分数. 思考历程 一看这题就知道是什么字符串方面的算 ...
- Android之GridLayout网格布局
1.相关属性 GridLayout网格布局是4.0之后引入的布局方式! android:columnCount="4" //设置列数(4列) android:rowCount=&q ...
- 版本控制git之四-忽略特殊文件
版本控制git之四-忽略特殊文件 有些时候,你必须把某些文件放到Git工作目录中,但又不能提交它们,比如保存了数据库密码的配置文件啦,等等,每次git status都会显示Untracked fi ...
- python3-常用模块之re
正则表达式 定义: 正则表达式是对字符串操作的一种逻辑公式,用事先定义好的一些特定字符.及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑. 是一种独立的规 ...
- Python爬取b站任意up主所有视频弹幕
爬取b站弹幕并不困难.要得到up主所有视频弹幕,我们首先进入up主视频页面,即https://space.bilibili.com/id号/video这个页面.按F12打开开发者菜单,刷新一下,在ne ...