HDU 5732 Subway(2016多校1J,树的重心 + 哈希)
题目链接 2016多校1 Problem J
题意 给定两棵相同的树,但是编号方案不同。求第一棵树上的每个点对应的第二棵树上的点。输出一种方案即可。
首先确定树的直径的中点。两棵树相等意味着两棵树的直径相等。
然而直径有很多条,我们任意求出两棵树的各一条直径并不以为着这两条直径是相对应的。
但是直径的中点一定是相对应的。
确定根结点后对整棵树哈希并进行匹配的这个过程是不难的。
当直径长度为偶数时中点有两个,那么最多做$4$次匹配就可以了。
这个哈希函数要好好设计,很容易产生冲突。
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i) typedef unsigned long long LL; const LL A = 90918567;
const LL B = 87378051;
const LL mod = 1e9 + 7;
const int N = 1e5 + 10; int a[N], ans[N], father[N], roota[3], rootb[3];
int numa, numb, n, x, y, c1, c2, L, R, cnt;
bool flag;
map <string, int> mp1, mp2;
vector <int> v[N], g[N];
string ss[N], tt[N], s1, s2;
LL c[N], f[N]; void init(){
mp1.clear();
mp2.clear();
rep(i, 0, n + 1) v[i].clear(), g[i].clear();
c1 = 0, c2 = 0;
} int get1(string s){
if (mp1.count(s)) return mp1[s];
mp1[s] = ++c1;
ss[c1] = s;
return c1;
} int get2(string s){
if (mp2.count(s)) return mp2[s];
mp2[s] = ++c2;
tt[c2] = s;
return c2;
} void dfs1(int x, int fa, int now, vector <int> v[N]){
if (now > c1){
c1 = now;
L = x;
} for (auto u : v[x]){
if (u == fa) continue;
dfs1(u, x, now + 1, v);
}
} void dfs2(int x, int fa, int now, vector <int> v[N]){
father[x] = fa;
if (now > c2){
c2 = now;
R = x;
} for (auto u : v[x]){
if (u == fa) continue;
dfs2(u, x, now + 1, v);
}
} void gethash_a(int x, int fa){
vector <LL> val;
for (auto u : v[x]){
if (u == fa) continue;
gethash_a(u, x);
val.push_back(c[u]);
} sort(val.begin(), val.end());
c[x] = B;
for (auto u : val){
c[x] = (c[x] * A ^ u) % mod;
}
} void gethash_b(int x, int fa){
vector <LL> val;
for (auto u : g[x]){
if (u == fa) continue;
gethash_b(u, x);
val.push_back(f[u]);
} sort(val.begin(), val.end()); f[x] = B;
for (auto u : val){
f[x] = (f[x] * A ^ u) % mod;
}
} bool cmp_a(const int &a, const int &b){
return c[a] < c[b];
} bool cmp_b(const int &a, const int &b){
return f[a] < f[b];
} void work(int x, int y, int fa_a, int fa_b){
vector <int> na, nb;
for (auto u : v[x]) if (u != fa_a) na.push_back(u);
for (auto u : g[y]) if (u != fa_b) nb.push_back(u); if ((int)na.size() != (int)nb.size()){
return;
} sort(na.begin(), na.end(), cmp_a);
sort(nb.begin(), nb.end(), cmp_b); int sz = (int)na.size(); rep(i, 0, sz - 1) if (c[na[i]] == f[nb[i]]) ans[na[i]] = nb[i]; rep(i, 0, sz - 1){
int u1 = na[i], u2 = nb[i];
work(u1, u2, x, y);
}
} bool solve(int roota, int rootb){
gethash_a(roota, 0);
gethash_b(rootb, 0); memset(ans, -1, sizeof ans); if (c[roota] != f[rootb]) return false; ans[roota] = rootb;
work(roota, rootb, 0, 0); bool ret = true;
rep(i, 1, n) if (ans[i] == -1){
ret = false;
break;
} return ret;
} void print(){
rep(i, 1, n) cout << ss[i] << " " << tt[ans[i]] << endl;
} int main(){ ios::sync_with_stdio(false); while (cin >> n){ init();
rep(i, 2, n){
cin >> s1 >> s2;
x = get1(s1);
y = get1(s2);
v[x].push_back(y);
v[y].push_back(x);
} rep(i, 2, n){
cin >> s1 >> s2;
x = get2(s1);
y = get2(s2);
g[x].push_back(y);
g[y].push_back(x);
} L = 0, R = 0;
c1 = 0, c2 = 0;
dfs1(1, 0, 0, v);
memset(father, 0, sizeof father);
dfs2(L, 0, 0, v); x = R;
cnt = 0;
numa = 0;
while (true){
a[++cnt] = R;
R = father[R];
if (R == 0) break;
} if (cnt & 1) roota[++numa] = a[(cnt + 1) / 2]; else{
roota[++numa] = a[cnt / 2];
roota[++numa] = a[cnt / 2 + 1];
} L = 0, R = 0;
c1 = 0, c2 = 0;
dfs1(1, 0, 0, g);
memset(father, 0, sizeof father);
dfs2(L, 0, 0, g); x = R;
cnt = 0;
numb = 0;
while (true){
a[++cnt] = R;
R = father[R];
if (R == 0) break;
} if (cnt & 1) rootb[++numb] = a[(cnt + 1) / 2]; else{
rootb[++numb] = a[cnt / 2];
rootb[++numb] = a[cnt / 2 + 1];
} flag = false;
rep(i, 1, numa){
rep(j, 1, numb){
if (solve(roota[i], rootb[j])){
flag = true;
print();
break;
}
}
if (flag) break;
}
} return 0;
}
HDU 5732 Subway(2016多校1J,树的重心 + 哈希)的更多相关文章
- HDU 5726 GCD (2016多校、二分、ST表处理区间GCD、数学)
题目链接 题意 : 给出一个有 N 个数字的整数数列.给出 Q 个问询.每次问询给出一个区间.用 ( L.R ) 表示.要你统计这个整数数列所有的子区间中有多少个和 GCD( L ~ R ) 相等.输 ...
- HDU 5727 Necklace ( 2016多校、二分图匹配 )
题目链接 题意 : 给出 2*N 颗珠子.有 N 颗是阴的.有 N 颗是阳的.现在要把阴阳珠子串成一个环状的项链.而且要求珠子的放置方式必须的阴阳相间的.然后给出你 M 个限制关系.格式为 ( A.B ...
- bzoj 3053 HDU 4347 : The Closest M Points kd树
bzoj 3053 HDU 4347 : The Closest M Points kd树 题目大意:求k维空间内某点的前k近的点. 就是一般的kd树,根据实测发现,kd树的两种建树方式,即按照方差 ...
- hdu 5274 Dylans loves tree(LCA + 线段树)
Dylans loves tree Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Othe ...
- 【HDU 5647】DZY Loves Connecting(树DP)
pid=5647">[HDU 5647]DZY Loves Connecting(树DP) DZY Loves Connecting Time Limit: 4000/2000 MS ...
- HDU 3074.Multiply game-区间乘法-线段树(单点更新、区间查询),上推标记取模
Multiply game Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Tot ...
- hdu 6200 mustedge mustedge(并查集+树状数组 或者 LCT 缩点)
hdu 6200 mustedge mustedge(并查集+树状数组 或者 LCT 缩点) 题意: 给一张无向连通图,有两种操作 1 u v 加一条边(u,v) 2 u v 计算u到v路径上桥的个数 ...
- HDU 1394 Minimum Inversion Number(线段树求最小逆序数对)
HDU 1394 Minimum Inversion Number(线段树求最小逆序数对) ACM 题目地址:HDU 1394 Minimum Inversion Number 题意: 给一个序列由 ...
- [HDU 5293]Tree chain problem(树形dp+树链剖分)
[HDU 5293]Tree chain problem(树形dp+树链剖分) 题面 在一棵树中,给出若干条链和链的权值,求选取不相交的链使得权值和最大. 分析 考虑树形dp,dp[x]表示以x为子树 ...
随机推荐
- cookie不能删除
cookie不仅仅包含一个键值对,还包含域 domain 路径path, 一般domain是请求的地址 www.baidu.com/news.html 那domain就是www.baidu.com ...
- App自动化测试前期准备---android SDK配置
说明:就是配置android SDK 一.sdk下载 Windows(X64):立即下载 Linux(X64):立即下载 二.Windows配置 1.解压文件 直接解压到指定目录(演示目录:D:/) ...
- python与execl的读写
[code=python] #复制execl中的部分数据到另一份execl中的相同位置 import xlrd import xlwt import xlutils.copy path1=" ...
- 孤荷凌寒自学python第五十八天成功使用python来连接上远端MongoDb数据库
孤荷凌寒自学python第五十八天成功使用python来连接上远端MongoDb数据库 (完整学习过程屏幕记录视频地址在文末) 今天是学习mongoDB数据库的第四天.今天的感觉是,mongoDB数据 ...
- Android之SQLite总结
SQLite 是一个轻量级的数据库,常用于各种嵌入式设备当中.android 提供了SQLiteOpenHelper的抽象类用于帮助开发数据库.在实际使用中经常定义一个类继承SQLiteOpenHel ...
- CentOS修改IP地址
一.CentOS 修改IP地址修改对应网卡的IP地址的配置文件 # vi /etc/sysconfig/network-scripts/ifcfg-eth0 电信 # vi /etc/syscon ...
- linux 环境下mysql忽略大小写
mysql数据库在window环境下默认是忽略大小写的,而linux环境中则相反,数据库移植过去后可能会影响到应用工程的正常使用. 解决方法: 用root帐号登录后,在/etc/my.cnf 中的[m ...
- 【转】PHP对象在内存中的分配
对像在PHP 里面和整型.浮点型一样,也是一种数据类,都是存储不同类型数据用的, 在运行的时候都要加载到内存中去用,那么对象在内存里面是怎么体现的呢?内存从逻辑上 说大体上是分为4 段,栈空间段.堆空 ...
- 【bzoj4994】[Usaco2017 Feb]Why Did the Cow Cross the Road III 树状数组
题目描述 给定长度为2N的序列,1~N各处现过2次,i第一次出现位置记为ai,第二次记为bi,求满足ai<aj<bi<bj的对数 样例输入 4 3 2 4 4 1 3 2 1 样例输 ...
- IO多路复用的理解
最近看了<后台开发核心技术与应用实践>有关select.poll和epoll部分以及相关的一些博客,学习了这三个函数的使用方法和区别,写一个易理解的总结. IO多路复用 之前程序中使用的I ...