zjuoj 3602 Count the Trees

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3602

Count the Trees


Time Limit: 2 Seconds      Memory Limit: 65536 KB


A binary tree is a tree data structure in which each node has at most two child nodes, usually distinguished as "left" and "right". A subtree of a tree T is a tree consisting of a node in T and all of its descendants in T. Two binary trees are called identical if their left subtrees are the same(or both having no left subtree) and their right subtrees are the same(or both having no right subtrees).

According to a recent research, some people in the world are interested in counting the number of identical subtree pairs, each from the given trees respectively.

Now, you are given two trees. Write a program to help to count the number of identical subtree pairs, such that the first one comes from the first tree and the second one comes from the second tree.

Input

There are multiple test cases. The first line contains a positive integer T (T ≤ 20) indicating the number of test cases. Then T test cases follow.

In each test case, There are two integers n and m (1 ≤ n, m ≤ 100000) indicating the number of nodes in the given two trees. The following n lines describe the first tree. The i-th line contains two integers u and v (1 ≤ u ≤ n or u = -1, 1 ≤ v ≤ n or v = -1) indicating the indices of the left and right children of node i. If u or v equals to -1, it means that node i don‘t have the corresponding left or right child. Then followed by m lines describing the second tree in the same format. The roots of both trees are node 1.

Output

For each test case, print a line containing the result.

Sample Input

2
2 2
-1 2
-1 -1
2 -1
-1 -1
5 5
2 3
4 5
-1 -1
-1 -1
-1 -1
2 3
4 5
-1 -1
-1 -1
-1 -1

Sample Output

1
11

Hint

The two trees in the first sample look like this.

References



Author: ZHUANG, Junyuan; WU, Zejun
Contest: The 9th Zhejiang Provincial Collegiate Programming Contest

AC代码:

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <algorithm>
 4
 5 using namespace std;
 6
 7 #define MAXN 100010
 8
 9 struct Edge {
10     int v, e, label;
11     Edge *link;
12 } edge[MAXN], *adj[MAXN];
13
14 int totE;
15 int f[MAXN], g[MAXN], val[MAXN], degree[MAXN], fa[MAXN];
16 int vec[2], Q[MAXN];
17 int a = 13, b = 7, pp = 11, q = 1000000007;
18
19 void addEdge(int u, int v, int label) {
20     Edge *p = &edge[totE++];
21     p->v = v;
22     p->label = label;
23     p->link = adj[u];
24     adj[u] = p;
25 }
26
27 void cal(int n, int f[MAXN]) {
28     totE = 0;
29     memset(adj, NULL, sizeof(adj));
30     memset(degree, 0, sizeof(degree));
31     for (int i = 1; i <= n; ++i) {
32         int l, r;
33         scanf("%d%d", &l, &r);
34         if (l != -1) {
35             addEdge(i, l, 137);
36             ++degree[i];
37             fa[l] = i;
38         }
39         if (r != -1) {
40             addEdge(i, r, 1007);
41             ++degree[i];
42             fa[r] = i;
43         }
44     }
45     int l = 0, r = 0;
46     for (int i = 1; i <= n; ++i) {
47         if (!degree[i])
48             Q[r++] = i;
49     }
50     while (l != r) {
51         int u = Q[l++];
52         Edge *p = adj[u];
53         int total = 0;
54         while (p) {
55             vec[total++] = (long long) val[p->v] * p->label % q;
56             p = p->link;
57         }
58         val[u] = a;
59         for (int i = 0; i < total; ++i) {
60             val[u] = (long long) val[u] * pp % q ^ vec[i] % q;
61         }
62         if(--degree[fa[u]] == 0) Q[r++] = fa[u];
63     }
64     for (int i = 1; i <= n; ++i)
65         f[i] = val[i];
66     sort(f + 1, f + 1 + n);
67 }
68
69 int main() {
70     int T;
71     scanf("%d", &T);
72     for (int cas = 1; cas <= T; ++cas) {
73         int n, m;
74         scanf("%d%d", &n, &m);
75         cal(n, f);
76         cal(m, g);
77         int p1 = 1, p2 = 1;
78         long long res = 0;
79         while (p1 <= n && p2 <= m) {
80             if (f[p1] > g[p2])
81                 ++p2;
82             else if (f[p1] < g[p2])
83                 ++p1;
84             else {
85                 int p3 = p1;
86                 while (p3 + 1 <= n && f[p3 + 1] == f[p1])
87                     ++p3;
88                 int p4 = p2;
89                 while (p4 + 1 <= m && g[p4 + 1] == g[p2])
90                     ++p4;
91                 res += (long long) (p3 - p1 + 1) * (p4 - p2 + 1);
92                 p1 = p3 + 1;
93                 p2 = p4 + 1;
94             }
95         }
96         printf("%lld\n", res);
97     }
98     return 0;
99 }

时间: 2024-11-07 10:23:50

zjuoj 3602 Count the Trees的相关文章

ZOJ 3602 Count the Trees 树的同构 (哈希)

链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4705 题意:给出两棵二叉树A和B,问分别处于A中的子树a和处于B中的子树b结构相同的有多少对. 思路:哈希的想法,不同的数字对应的是不同的结构,比如1代表着单独的叶子结点,2代表着有左子树是叶子结点而没有右子树的子树...每出现一种新的子树情形就记录下来,记录的方式是用dfs回溯过程中判断左子树和右子树组成的子树是否出现过(用pair记录子树的情况,也就是左右子树,两个

ZOJ 3602 Count the Trees

题意: 两棵树(10^5个节点)  问其中有多少对子树是同构的 思路: 树的同构一般使用hash来判断 hash函数为1.val=A   2.val = (val*P)^Soni%Q  其中Soni为第i个子树的hash值  3.val=val*B%Q 注意Son值应该排序  (本题因为左右子树是区分开的  因此不用排序) 代码: #include<cstdio> #include<iostream> #include<cstring> #include<stri

Count the Trees 典型卡特兰数

Count the Trees 题目分析:给你n个分别标为1,2,...,n的节点,问可以构成多少棵而叉树. 分析:首先考虑n个节点是相同的.任选一个节点做跟节点,那么剩下的n-1个节点构成跟节点的左子树和又子数. h[n] = h[0] * h[n-1] + h[1] * h[n - 2] + ... + h[n-1] * h[0];这正是卡特蓝表达式. h[n] = h[n-1] * (4 * n - 2) / (n + 1).   h[n] = C(2 * n,n)/(n + 1); 对于

UVa 10007 &amp; hdu 1131 Count the Trees (卡特兰数)

Count the Trees Time Limit:3000MS    Memory Limit:0KB     64bit IO Format:%lld & %llu SubmitStatus Description  Count the Trees  Another common social inability is known as ACM (Abnormally Compulsive Meditation). This psychological disorder is somewh

4292: Count the Trees(树hash)

4292: Count the Trees  时间限制(普通/Java):2000MS/6000MS     内存限制:65536KByte总提交: 15            测试通过:6 描述 A binary tree is a tree data structure in which each node has at most two child nodes, usually distinguished as "left" and "right". A su

UVa 10007 - Count the Trees

题目:统计n个节点的二叉树的个数. 分析:组合,计数,卡特兰数,大整数. n个节点的二叉树的形状有Cn个,求不同的树的个数,用卡特兰数乘以全排列n! 说明:打表计算,查询输出,提高效率. #include <iostream> #include <cstdlib> #include <cstdio> using namespace std; int C[305][2005] = {0}; int main() { C[1][0] = 1; for (int i = 2

HDU 1131 Count the Trees 大数计算

题目是说给出一个数字,然后以1到这个数为序号当做二叉树的结点,问总共有几种组成二叉树的方式.这个题就是用卡特兰数算出个数,然后因为有编号,不同的编号对应不同的方式,所以结果是卡特兰数乘这个数的阶乘种方案.因为数字比较大,所以要用高精度的方法也就是用字符数组来做,我分别写了三个函数,一个算加法,一个算乘法,最后一个打表,等打出表来最后只要判断一下输入的数是第几个,直接输出就行了,下面是我的代码,第一次写高精度的这种大数处理,可能看上去比较繁琐= = #include<iostream> #inc

UVa 10007 - Count the Trees(卡特兰数+阶乘+大数)

题目链接:UVa 10007 题意:统计n个节点的二叉树的个数 1个节点形成的二叉树的形状个数为:1 2个节点形成的二叉树的形状个数为:2 3个节点形成的二叉树的形状个数为:5 4个节点形成的二叉树的形状个数为:14 5个节点形成的二叉树的形状个数为:42 把n个节点对号入座有n!种情况 所以有n个节点的形成的二叉树的总数是:卡特兰数F[n]*n! 程序: 1 import java.math.BigInteger; 2 import java.util.Scanner; 3 public cl

hdu 1131 Count the Trees

卡特兰数*阶乘就是答案     第一次用java..高精度写起来好快....不过代码比较丑.. import java.math.BigInteger; import java.util.Scanner; public class Main { public static void main(String []args) { Scanner cin = new Scanner(System.in); int i,ii; BigInteger []c= new BigInteger[105]; B