一棵树的子树数量

原题Who killed Cock Robin

题意

给出一颗无根树,问有多少种子图(包括点)

解析

既然无根树,那么就随便选择一个点为rt,就1好了

用x[i]表示以i点为父亲得到的图的可能性
对于每个点i,儿子数为0时,x[i]为0,有n个儿子时,对于每个儿子j所能产生的可能性为x[j]+1,而x[i]为随便选任意个儿子相乘之和

eg:有三个儿子可能性为2 3 4,可能得到的就是3 4 5
那么x[i]=3+4+5+3*4+4*5+3*5+3*4*5

任意乘有个公式:dp[i]=dp[i-1]*x[i]+x[i] (dp[i]为前i个数的任意乘)
因为3和4有3,4,3*4,加入5多了5,3*5,4*5,3*4*5,多了的部分就是5*前面部分加一个5

另外,x[儿子]和x[父亲]都要加到ans里面,因为以父亲为root的那部分是从父亲开始往下延的,而x[儿子]是以儿子为root的

代码

#define N 100009
int n;
vector<int>v[2*N];
D Ans=0;

D fin(int ar,int fa){
    int haveson=0;
    queue<D>Q;
    for(int i=0;i<v[ar].size();i++){
        if(v[ar][i]==fa)continue;
        D add=fin(v[ar][i],ar)+1;
        Q.push(add);
    }
    D ans=0;
    while(!Q.empty()){
        ans+=ans*Q.front()%mod;ans=(ans+Q.front())%mod;Q.pop();
    }
    Ans=(Ans+ans)%mod;
    return ans;
}

int main(){
    cin>>n;
    Ans+=n;
    for(int i=1;i<=n-1;i++){
        int a,b;scanf("%d%d",&a,&b);
        v[a].push_back(b);
        v[b].push_back(a);
    }
    fin(1,0);
    printf("%lld\n",Ans);
}
<think>我们面对的问题是如何将两棵树合并成一棵树。树是数据结构中的一种常见形式,合并操作通常需要根据树的具体类型(如二叉树、二叉搜索树、普通树等)和合并规则(如合并相同位置的节点、合并为新的结构等)来进行。由于问题没有指定树的类型,我们将考虑几种常见情况。 常见的树合并方法包括: 1. 递归合并:如果两棵树结构相似(如同为二叉树),可以递归地合并对应节点。 2. 遍历合并:通过遍历两棵树,将节点收集起来,然后构建一棵新树。 3. 特定类型树的合并:如二叉搜索树可以通过中序遍历得到有序数组,然后合并两个有序数组再重建二叉搜索树。 由于问题描述较为宽泛,这里将介绍两种常见场景的合并方法:普通二叉树的合并(节点值合并)和二叉搜索树的合并。 ### 方法1:普通二叉树的合并(对应位置节点值相加) 假设两棵二叉树的结构相同(即对应位置都有节点或都没有节点),我们可以将对应节点的值相加。如果结构不同,可以在缺失的位置用0补充。 递归合并步骤: - 如果两棵树都为空,返回空。 - 如果其中一棵树为空,则以0作为该节点的值,继续合并(或者直接使用另一棵树的节点,但这里我们要求合并节点值,所以用0)。 - 如果两个节点都存在,则新节点的值为两个节点值之和。 - 递归合并左子树和右子树。 示例代码(Python): ```python class TreeNode: def __init__(self, val=0, left=None, right=None): self.val = val self.left = left self.right = right def mergeTrees(t1, t2): if not t1 and not t2: return None val1 = t1.val if t1 else 0 val2 = t2.val if t2 else 0 new_val = val1 + val2 new_node = TreeNode(new_val) new_node.left = mergeTrees(t1.left if t1 else None, t2.left if t2 else None) new_node.right = mergeTrees(t1.right if t1 else None, t2.right if t2 else None) return new_node ``` ### 方法2:二叉搜索树的合并 二叉搜索树(BST)的中序遍历是有序的。合并两棵二叉搜索树,可以分别得到它们的中序遍历序列,然后合并两个有序数组,再根据合并后的有序数组重建一棵二叉搜索树。 步骤: 1. 对两棵BST分别进行中序遍历,得到两个有序数组。 2. 合并两个有序数组(归并排序的合并过程)。 3. 根据合并后的有序数组构建一棵平衡的BST(可以使用二分法递归构建)。 示例代码(Python): ```python def inorder(root, arr): if root: inorder(root.left, arr) arr.append(root.val) inorder(root.right, arr) def mergeSortedArrays(arr1, arr2): merged = [] i, j = 0, 0 while i < len(arr1) and j < len(arr2): if arr1[i] < arr2[j]: merged.append(arr1[i]) i += 1 else: merged.append(arr2[j]) j += 1 while i < len(arr1): merged.append(arr1[i]) i += 1 while j < len(arr2): merged.append(arr2[j]) j += 1 return merged def sortedArrayToBST(arr): if not arr: return None mid = len(arr) // 2 root = TreeNode(arr[mid]) root.left = sortedArrayToBST(arr[:mid]) root.right = sortedArrayToBST(arr[mid+1:]) return root def mergeBSTs(t1, t2): arr1 = [] arr2 = [] inorder(t1, arr1) inorder(t2, arr2) merged_arr = mergeSortedArrays(arr1, arr2) return sortedArrayToBST(merged_arr) ``` ### 方法3:普通树的合并(基于子节点列表) 如果树不是二叉树,而是每个节点有多个子节点(如n叉树),合并方法可以是: - 将两棵树相同位置的节点合并(节点值相加或其他操作),然后递归合并它们的子节点。 - 需要处理子节点数量不一致的情况,可以以子节点数量多的那棵树为基准,另一棵树缺失的位置用空节点代替。 由于普通树的结构差异较大,具体实现需要根据树的具体定义来调整。 ### 注意事项 - 在合并过程中,如果节点包含的数据不仅仅是数值(如还有其他属性),合并规则需要扩展。 - 如果树的结构差异很大,合并后可能形成一棵新的结构不同的树。 以上方法提供了不同树结构的合并思路。实际应用中,需要根据具体需求选择合适的合并策略。 §§相关问题§§: 1. 如何合并两棵二叉搜索树并保持平衡? 2. 如果两棵二叉树结构不同,如何安全地合并它们? 3. 合并两棵树时如何处理节点值以外的属性?</think>### 合并两棵树的方法 以下是不同树结构下的合并方法,根据树的类型选择合适方案: --- #### **1. 二叉树合并(节点值相加)** 适用于两棵结构相似的二叉树,合并规则为对应节点值相加: ```python class TreeNode: def __init__(self, val=0, left=None, right=None): self.val = val self.left = left self.right = right def mergeTrees(root1, root2): if not root1: return root2 if not root2: return root1 # 节点值相加 merged = TreeNode(root1.val + root2.val) # 递归合并左右子树 merged.left = mergeTrees(root1.left, root2.left) merged.right = mergeTrees(root1.right, root2.right) return merged ``` - **时间复杂度**:$O(\min(m,n))$($m,n$ 为两棵树节点数) - **空间复杂度**:$O(\min(m,n))$(递归栈深度) --- #### **2. 二叉搜索树(BST)合并** 通过中序遍历获取有序数组,再合并数组重建BST: ```python def inorder(root, arr): if root: inorder(root.left, arr) arr.append(root.val) inorder(root.right, arr) def mergeBSTs(root1, root2): arr1, arr2 = [], [] inorder(root1, arr1) inorder(root2, arr2) # 合并有序数组 merged_arr = [] i = j = 0 while i < len(arr1) and j < len(arr2): if arr1[i] < arr2[j]: merged_arr.append(arr1[i]) i += 1 else: merged_arr.append(arr2[j]) j += 1 merged_arr.extend(arr1[i:] or arr2[j:]) # 有序数组重建BST def build_bst(arr, l, r): if l > r: return None mid = (l + r) // 2 root = TreeNode(arr[mid]) root.left = build_bst(arr, l, mid-1) root.right = build_bst(arr, mid+1, r) return root return build_bst(merged_arr, 0, len(merged_arr)-1) ``` - **时间复杂度**:$O(m + n)$(遍历和数组合并) - **空间复杂度**:$O(m + n)$(存储中序序列) --- #### **3. 通用树合并(子节点列表处理)** 适用于多子节点的树结构(如N叉树),合并相同层级的子节点: ```python class Node: def __init__(self, val=None, children=None): self.val = val self.children = children if children else [] def merge_trees(root1, root2): if not root1: return root2 if not root2: return root1 # 合并节点值(示例为相加) merged = Node(root1.val + root2.val) # 合并子节点列表 max_len = max(len(root1.children), len(root2.children)) for i in range(max_len): child1 = root1.children[i] if i < len(root1.children) else None child2 = root2.children[i] if i < len(root2.children) else None merged.children.append(merge_trees(child1, child2)) return merged ``` --- ### **关键注意事项** - **树结构一致性**:二叉树合并需结构相似,BST合并需保持有序性。 - **自定义合并规则**:上述示例为节点值相加,可替换为其他操作(如取最大值)。 - **空树处理**:任一树为空时直接返回另一棵树。 - **内存优化**:BST合并可优化为 $O(1)$ 额外空间(Morris遍历+链表合并)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值