题目链接  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,树的重心 + 哈希)的更多相关文章

  1. HDU 5726 GCD (2016多校、二分、ST表处理区间GCD、数学)

    题目链接 题意 : 给出一个有 N 个数字的整数数列.给出 Q 个问询.每次问询给出一个区间.用 ( L.R ) 表示.要你统计这个整数数列所有的子区间中有多少个和 GCD( L ~ R ) 相等.输 ...

  2. HDU 5727 Necklace ( 2016多校、二分图匹配 )

    题目链接 题意 : 给出 2*N 颗珠子.有 N 颗是阴的.有 N 颗是阳的.现在要把阴阳珠子串成一个环状的项链.而且要求珠子的放置方式必须的阴阳相间的.然后给出你 M 个限制关系.格式为 ( A.B ...

  3. bzoj 3053 HDU 4347 : The Closest M Points kd树

    bzoj 3053 HDU 4347 : The Closest M Points  kd树 题目大意:求k维空间内某点的前k近的点. 就是一般的kd树,根据实测发现,kd树的两种建树方式,即按照方差 ...

  4. hdu 5274 Dylans loves tree(LCA + 线段树)

    Dylans loves tree Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Othe ...

  5. 【HDU 5647】DZY Loves Connecting(树DP)

    pid=5647">[HDU 5647]DZY Loves Connecting(树DP) DZY Loves Connecting Time Limit: 4000/2000 MS ...

  6. HDU 3074.Multiply game-区间乘法-线段树(单点更新、区间查询),上推标记取模

    Multiply game Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Tot ...

  7. hdu 6200 mustedge mustedge(并查集+树状数组 或者 LCT 缩点)

    hdu 6200 mustedge mustedge(并查集+树状数组 或者 LCT 缩点) 题意: 给一张无向连通图,有两种操作 1 u v 加一条边(u,v) 2 u v 计算u到v路径上桥的个数 ...

  8. HDU 1394 Minimum Inversion Number(线段树求最小逆序数对)

    HDU 1394 Minimum Inversion Number(线段树求最小逆序数对) ACM 题目地址:HDU 1394 Minimum Inversion Number 题意:  给一个序列由 ...

  9. [HDU 5293]Tree chain problem(树形dp+树链剖分)

    [HDU 5293]Tree chain problem(树形dp+树链剖分) 题面 在一棵树中,给出若干条链和链的权值,求选取不相交的链使得权值和最大. 分析 考虑树形dp,dp[x]表示以x为子树 ...

随机推荐

  1. groupNoAdj

    public boolean groupNoAdj(int start, int[] nums, int target) { if( start >= nums.length){ return ...

  2. 《Cracking the Coding Interview》——第12章:测试——题目5·

    2014-04-25 00:41 题目:怎么测试一支笔?(Pen?您老说的是钢笔?) 解法:这种简约而不简单的题目,实在是面试官最喜欢,面试者最头疼的类型了.面试官可以只花三秒,以一种灰常高贵冷艳的语 ...

  3. js 请求异常重连或断线后联网重连机制(ajax)

    转到到 https://blog.csdn.net/mengtoumingren/article/details/80296788

  4. Nova 如何统计 OpenStack 资源

    1.云计算的本质在于将硬件资源软件化,以达到快速按需交付的效果,最基本的计算.存储和网络基础元素并没有因此改变.就计算而言,CPU.RAM 和 DISK等依旧是必不可少的核心资源. 从源代码和数据库相 ...

  5. Python中的多线程编程,线程安全与锁(二)

    在我的上篇博文Python中的多线程编程,线程安全与锁(一)中,我们熟悉了多线程编程与线程安全相关重要概念, Threading.Lock实现互斥锁的简单示例,两种死锁(迭代死锁和互相等待死锁)情况及 ...

  6. SQL Server 获取满足条件的每个条件下的前N条数据

    从数据库获取数据时,经常会遇到获取一个数据列表和该列表中每条数据对应的另一个列表的情况,如果二级列表获取的是全部数据,那么就比较简单.如果二级列表获取的是前n条数据,就会比较麻烦. 从操作上来看,好像 ...

  7. 【Luogu】P3760异或和(权值树状数组)

    题目链接 再次声明以后我见到位运算一定第一时间想把它拆成每一位算 本题就是有个前缀和sum[],然后让你求每一位有多少对i,j满足sum[i]-sum[j]在那一位上是1 考虑怎样才能减出1来 如果s ...

  8. MPLAB设置路径

    大家都知道在MPLAB环境下编译程序,c文件.h文件.编译器生成的文件等等,都会被编译器无情的放在一个项目文件夹下. 稍微有些讲究的程序员可能就会觉得用MPLAB项目组织的一团糟.于是大家想到了一种方 ...

  9. HDU 1007 Quoit Design | 平面分治

    暂鸽 #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #d ...

  10. 刷题总结——Aeroplane chess(hdu4405)

    题目: Problem Description Hzz loves aeroplane chess very much. The chess map contains N+1 grids labele ...