哈希-蔡老板分果子

Posted ghcred

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了哈希-蔡老板分果子相关的知识,希望对你有一定的参考价值。

#238. 蔡老板分果子

 统计

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

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

输入格式

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

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

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

输出格式

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

样例1

input

4
1 2
2 3
3 4
1 2
1 3
3 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

6
1 2
1 3
2 4
2 5
3 6
1 4
4 2
4 5
2 3
3 6

output

3

样例3

见样例数据下载

限制与规定

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

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

子任务编号分值nn其他限制
1 4 10≤10
2 19 100≤100
3 20 103≤103
4 21 2×105≤2×105 保证所有点的度数不超过 22
5 36 2×105≤2×105

时间限制:1s1s

空间限制:256MB256MB

下载

样例数据下载

 

需要设计一个哈希函数与树的形态和父子关系无关。想到了 (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 {
18     ull a, b;
19     
20     bool operator < (const data &tmp) const
21     {
22         return a == tmp.a ? b < tmp.b : a < tmp.a;
23     }
24     
25     bool operator == (const data &tmp) const
26     {
27         return a == tmp.a && b == tmp.b;
28     }
29 } A[2][_N];
30 
31 ull Mont(ull a)
32 {
33     a %= P;
34     ull t = 1, b = 131;
35     while (b) {
36         if (b & 1) t = t*a%P;
37         b >>= 1, a = a*a%P;
38     }
39     return t;
40 }
41 
42 void DFS(int id, int node, int dad)
43 {
44     A[id][node].a = hs[node], A[id][node].b = Mont(hs[node]);
45     for (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     }
52     return;
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 {
59     G[id][x].push_back(y), G[id][y].push_back(x);
60     return;
61 }
62 
63 int main()
64 {
65     int i, j, id;
66     srand(19260817);
67     scanf("%d", &N);
68     for (i = 1; i <= N; ++i) hs[i] = umul(umul(rand(), rand()), rand())+rand()%97;
69     for (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         }
75     for (id = 0; id <= 1; ++id)
76         DFS(id, 1, -1), sort(A[id]+1, A[id]+1+N);
77     i = j = 1;
78     int ans = 0;
79     while (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     }
84     printf("%d
", ans-1);
85     return 0;
86 }

 

以上是关于哈希-蔡老板分果子的主要内容,如果未能解决你的问题,请参考以下文章

Symfony2 将哈希片段参数附加到分页 URL

codevs 1766 分果子

把二叉树揉碎

冲刺贡献分

下文中的哈希片段指的是啥?

URL片段的最大长度(哈希)