100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > 哈希/图论-蔡老板分果子

哈希/图论-蔡老板分果子

时间:2020-08-28 23:36:16

相关推荐

哈希/图论-蔡老板分果子

#238. 蔡老板分果子

统计

描述提交自定义测试

春天来了,万物复苏,动物们又到了发情的季节。蔡老板终于下定决心砍下了自家后院的两棵果树,并决定和自己喜欢的人一起分享果树上的果子。

这两棵果树一棵是长生果树另一棵是人参果树,两棵树上都有nn个果子,编号为1∼n1∼n,并分别由n−1n−1段树枝连接起来。 为了把果子分成两份,蔡老板决定再两棵树上各砍一刀,分别砍断一根树枝把两棵树上的果子各分成两个部分。之后,对于每一棵果树,蔡老板会选择11号果子所在的那一部分。显然这样分果子一共有(n−1)2(n−1)2种分法,而蔡老板想知道,有多少种切割方法,使得蔡老师拿到的长生果和人参果具有相同的标号集合。

输入格式

第一行一个正整数nn表示两棵树的大小。

接下来n−1n−1行每行两个正整数表示长生果树上的边。

接下来n−1n−1行每行两个正整数表示人参果树上的边。

输出格式

输出一行一个正整数表示蔡老板关心的切割方法的数目。

样例1

input

41 22 33 41 21 33 4

output

2

explanation

第一种切割方法:第一棵树上切(2,3)(2,3),第二棵树上切(1,3)(1,3),这样蔡老师拿到的长生果和人参果集合都是{1,2}{1,2};

第二种切割方法:第一棵树上切(3,4)(3,4),第二棵树上切(3,4)(3,4),这样蔡老师拿到的长生果和人参果集合都是{1,2,3}{1,2,3}。

样例2

input

61 21 32 42 53 61 44 24 52 33 6

output

3

样例3

见样例数据下载

限制与规定

对于全部数据1≤n≤2×105.1≤n≤2×105.

本题采用捆绑测试,只有通过一个子任务的全部测试点才可以获得该子任务的分数,子任务及限制如下表所示:

时间限制:1s1s

空间限制:256MB256MB

下载

样例数据下载

法1. 对子树哈希

需要设计一个哈希函数与树的形态和父子关系无关。想到了 (ap+bp)%q 这类哈希函数,会被卡掉。正解是直接用 xor 哈希,然后提前把 [1, N] 映射到一个 unsigned long long 的整数。据说(也可以感性感受到)这样的好处是每一位的影响是独立的。也就是说,只有每一位都冲突,两个哈希函数才可能冲突。这样就可以过。代码里把幂数和和异或和作为两个参数搞了一个双哈,不过真正起作用的是异或和。

1 #include <stdio.h> 2 #include <algorithm> 3 #include <vector> 4 #include <stdlib.h> 5 6 using namespace std; 7 8 typedef unsigned long long ull; 9 10 const int _N = 220000;11 const ull P = 1e9+7;12 13 ull hs[_N];14 vector<int> G[2][_N];15 int N;16 17 struct data {18ull a, b;1920bool operator < (const data &tmp) const21{22 return a == tmp.a ? b < tmp.b : a < tmp.a;23}2425bool operator == (const data &tmp) const26{27 return a == tmp.a && b == tmp.b;28}29 } A[2][_N];30 31 ull Mont(ull a)32 {33a %= P;34ull t = 1, b = 131;35while (b) {36 if (b & 1) t = t*a%P;37 b >>= 1, a = a*a%P;38}39return t;40 }41 42 void DFS(int id, int node, int dad)43 {44A[id][node].a = hs[node], A[id][node].b = Mont(hs[node]);45for (int i = G[id][node].size()-1; i >= 0; --i) {46 int v = G[id][node][i];47 if (v != dad) {48 DFS(id, v, node);49 A[id][node].a = A[id][node].a^A[id][v].a, A[id][node].b = (A[id][node].b+A[id][v].b)%P;50 }51}52return;53 }54 55 inline ull umul(int a, int b) { return (ull)a * b; }56 57 void Ins(int id, int x, int y)58 {59G[id][x].push_back(y), G[id][y].push_back(x);60return;61 }62 63 int main()64 {65int i, j, id;66srand(19260817);67scanf("%d", &N);68for (i = 1; i <= N; ++i) hs[i] = umul(umul(rand(), rand()), rand())+rand()%97;69for (id = 0; id <= 1; ++id)70 for (i = 1; i < N; ++i) {71 int x, y;72 scanf("%d%d", &x, &y);73 Ins(id, x, y);74 }75for (id = 0; id <= 1; ++id)76 DFS(id, 1, -1), sort(A[id]+1, A[id]+1+N);77i = j = 1;78int ans = 0;79while (i <= N && j <= N) {80 if (A[0][i] == A[1][j]) ++ans, ++i;81 else if (A[0][i] < A[1][j]) ++i;82 else ++j;83}84printf("%d\n", ans-1);85return 0;86 }

法2. 机智的 dfs 序

设两棵树为 A, B 。对 A 树进行 DFS,记录每个节点的 dfn[i] 以及 size[i] 。然后对 B 树进行 DFS,记录每个节点对应的 dfn[i] 值的 max[i] 和 min[i] 以及 size2[i] 。则此时 B 某子树与 A 的某子树可以以及为答案贡献的充要条件是 size2[i] = size[i] 且 max[i]-min[i]+1 = size[i] 。思路大概就是,当这两个条件同时成立时,B 的子树中节点对应的 dfn[i] 值(注意此处的 dfn 是指在对 A 进行 DFS 得到的某个点的 dfn)一定构成了 [min[i], max[i]] 这段连续的区间。而 A 中对应子树的 dfn 编号也是这段连续区间(连续性显然……OrzOrz)。这个方法非常机智,而且好写!

1 #include <stdio.h> 2 #include <vector> 3 #include <algorithm> 4 5 using namespace std; 6 7 const int _N = 220000; 8 9 int A[_N], B[_N], dfn[_N], size[_N], ans, Time, s2[_N];10 vector<int> G[2][_N];11 12 void DFS2(int node, int dad)13 {14A[node] = B[node] = dfn[node];15s2[node] = 1;16for (int i = G[1][node].size()-1; i >= 0; --i) {17 int v = G[1][node][i];18 if (v != dad) {19 DFS2(v, node);20 A[node] = min(A[node], A[v]), B[node] = max(B[node], B[v]);21 s2[node] += s2[v];22 }23}24if (B[node]-A[node]+1 == size[A[node]] && size[A[node]] == s2[node])25 ++ans;26return;27 }28 29 void DFS(int node, int dad)30 {31dfn[node] = ++Time;32size[dfn[node]] = 1;33for (int i = G[0][node].size()-1; i >= 0; --i) {34 int v = G[0][node][i];35 if (v != dad) {36 DFS(v, node);37 size[dfn[node]] += size[dfn[v]];38 }39}40return;41 }42 43 void Ins(int id, int x, int y)44 {45G[id][x].push_back(y), G[id][y].push_back(x);46return;47 }48 49 int main()50 {51int N, i, id;52scanf("%d", &N);53for (id = 0; id <= 1; ++id)54 for (i = 1; i < N; ++i) {55 int x, y;56 scanf("%d%d", &x, &y);57 Ins(id, x, y);58 }59DFS(1, -1);60DFS2(1, -1);61printf("%d\n", ans-1);62return 0;63 }

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。