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为子树 ...
随机推荐
- 《Cracking the Coding Interview》——第18章:难题——题目6
2014-04-29 02:27 题目:找出10亿个数中最小的100万个数,假设内存可以装得下. 解法1:内存可以装得下?可以用快速选择算法得到无序的结果.时间复杂度总体是O(n)级别,但是常系数不小 ...
- USACO Section1.5 Superprime Rib 解题报告
sprime解题报告 —— icedream61 博客园(转载请注明出处)--------------------------------------------------------------- ...
- win10 ubuntu16双系统安装教程
一. 知识准备 1.材料 前提: 本文档是在win10 64位下进行安装的!32位的安装注意其中的一些细节即可 硬件: X86_64 位电脑 硬盘有 40G 空闲 软件:[百度搜索即可] (1) Ul ...
- URAL 1944 大水题模拟
D - Record of the Attack at the Orbit Time Limit:1000MS Memory Limit:65536KB 64bit IO Format ...
- HTML5的JavaScript选择器介绍
在HTML5出现之前使用JavaScript查找DOM元素,有以下三种原生的方法: getElementById:根据指定元素的id属性返回元素 getElementsByName:返回所有指定nam ...
- LeetCode -- Valid Parenthese
Question: Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine i ...
- [UOJ#131][BZOJ4199][NOI2015]品酒大会
[UOJ#131][BZOJ4199][NOI2015]品酒大会 试题描述 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个 ...
- BZOJ5300 [Cqoi2018]九连环 【dp + 高精】
题目链接 BZOJ5300 题解 这题真的是很丧病,,卡高精卡到哭 我们设\(f[i]\)表示卸掉前\(i\)个环需要的步数 那么 \[f[i] = 2*f[i - 2] + f[i - 1] + 1 ...
- 【CF Edu 28 B. Math Show】
time limit per test 1 second memory limit per test 256 megabytes input standard input output standar ...
- linux中sed工具的使用
sed 本身也是一个管线命令,而且 sed 还可以将数据进行取代.删除.新增.撷取特定行等等的功能. $ sed [-nefr] [动作] 选项与参数: -n :使用安静(silent)模式.在一般 ...