树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 ...
随机推荐
- 谈谈HINT /*+parallel(t,4)*/在SQL调优中的重要作用
/*+parallel(t,4)*/在大表查询等操作中能够起到良好的效果,基于并行查询要启动并行进程.分配任务与系统资源.合并结果集,这些都是比较消耗资源,但我们为能够减少执行事务的时间使用paral ...
- Redis单机和集群配置(版本在5.0后)
摘抄并用于自己后查 单机版的配置: 1. 下载redis压缩包,然后解压缩文件(tar xzf): 2. 进入解压后的redis文件目录,编译redis源文件(make,没有c环境要gcc): 3. ...
- 【核心核心】10.Spring事务管理【TX】XML+注解方式
转账案例环境搭建 1.引入JAR包 IOC的6个包 AOP的4个包 C3P0的1个包 MySQL的1个驱动包 JDBC的2个目标包 整合JUnit测试1个包 2.引入配置文件 log4j.proper ...
- vue/cli 3.0脚手架搭建
在vue 2.9.6中,搭建vue-cli脚手架的流程是这样的: 首先 全局安装vue-cli,在cmd中输入命令: npm install --global vue-cli 安装成功: 安装完成 ...
- 【JZOJ2288】【BZOJ1898】【luoguP2579】沼泽鳄鱼
description 潘塔纳尔沼泽地号称世界上最大的一块湿地,它地位于巴西中部马托格罗索州的南部地区.每当雨季来临,这里碧波荡漾.生机盎然,引来不少游客. 为了让游玩更有情趣,人们在池塘的中央建设了 ...
- HTML - 文本标签相关
<html> <head></head> <body> <!-- 标题标签 : h1到h6, 文字大小依次变小, 加粗显示, 自带换行 标签中的部 ...
- Element-ui之修改样式
修改样式的方法 官网上面介绍了几种方法: 当然还有其他的方法,比如: 直接在标签上面采用行内式: 在组件中的style里面添加样式: 引入.scss文件(注意:如果是公用样式最好在index.scss ...
- 线性回归和梯度下降代码demo
程序所用文件:https://files.cnblogs.com/files/henuliulei/%E5%9B%9E%E5%BD%92%E5%88%86%E7%B1%BB%E6%95%B0%E6%8 ...
- disruptor 高效队列
disruptor 是什么: disruptor 是一个 低延时的 无锁 环形 队列. 相较于 java的 队列 ,他有明显的优点 ,无界,无锁,低延时(解决了为内存共享问题 ) disrupto ...
- <爬虫>利用BeautifulSoup爬取百度百科虚拟人物资料存入Mysql数据库
网页情况: 代码: import requests from requests.exceptions import RequestException from bs4 import Beautiful ...