【CSP-S 2019】括号树(洛谷P5658):栈+DFS

深度学习
• 阅读 3

【CSP-S 2019】括号树(洛谷P5658):栈+DFS 一、题目解读 括号树问题(洛谷P5658)要求处理一个由括号序列转化的树结构:每个节点表示一个括号,'('为子节点,')'为父节点。题目给定一棵n个节点的树,需计算每个节点的深度(括号层数),并输出所有节点深度与节点编号乘积的异或和。核心在于将括号序列转化为树,并高效计算深度信息。

二、解题思路 采用“栈+深度优先搜索(DFS)”的策略:

  1. 栈处理括号匹配:用栈维护未匹配的左括号,遇到')'时弹出栈顶,建立父子关系。

  2. 树构建与深度计算:通过父节点输入建立树结构,DFS遍历时利用栈弹出更新深度(dp值)。

  3. 累积深度和:sum数组记录子树深度总和,避免重复计算。

  4. 异或求解:最终遍历所有节点,异或乘积i*sum[i]得到答案。

三、解题步骤

  1. 输入处理:读入n、括号序列s及父节点数组fa,构建树边tree。

  2. DFS遍历:从根节点1开始,递归处理子节点:

    遇到'('入栈,')'时弹出并更新dp(深度继承父节点+1)。

    累加sum:sum[u] = sum[父节点] + dp[u]。

  3. 异或计算:遍历节点i,异或值i*sum[i]累加至ans。

四、代码与注释

#include <iostream>
#include <vector>
#include <stack>
using namespace std;

const int MAXN = 5e5 + 10; // 节点数上限
vector<int> tree[MAXN]; // 邻接表存树
char s[MAXN]; // 括号序列
int fa[MAXN]; // 父节点数组
long long dp[MAXN], sum[MAXN]; // 深度、子树深度和
stack<int> stk; // 存储未匹配左括号

void dfs(int u) { // 递归遍历节点u
    int last = 0; // 记录匹配的右括号
    if (s[u] == '(') { // 左括号入栈
        stk.push(u);
    } else if (!stk.empty()) { // 匹配右括号
        last = stk.top(); // 获取栈顶(父节点)
        stk.pop(); // 弹出
        dp[u] = dp[fa[last]] + 1; // 继承深度+1
    }

    sum[u] = sum[fa[u]] + dp[u]; // 累加子树深度和

    for (int v : tree[u]) { // 遍历子节点
        dfs(v);
    }

    if (s[u] == '(') { // 左括号处理(特判栈顶是否自匹配)
        if (!stk.empty() && stk.top() == u) {
            stk.pop();
        }
    } else if (last!= 0) { // 右括号入栈(父节点)
        stk.push(last);
    }
}

int main() {
    ios::sync_with_stdio(false); // 关闭同步加速输入
    cin.tie(nullptr);

    int n;
    cin >> n; // 读入节点数
    cin >> (s + 1); // 读入括号序列(从s[1]开始)

    for (int i = 2; i <= n; ++i) { // 建立树边(从2开始)
        cin >> fa[i];
        tree[fa[i]].push_back(i);
    }

    dfs(1); // 从根节点开始DFS

    long long ans = 0;
    for (int i = 1; i <= n; ++i) {
        ans ^= (i * sum[i]); // 异或乘积
    }

    cout << ans << endl;
    return 0;
}

五、总结

  1. 核心思想:通过栈维护括号匹配关系,将序列转化为树结构,利用DFS高效计算深度信息。

  2. 优化点:

累积sum数组避免重复深度求和。

异或运算简化最终答案计算。

  1. 复杂度:O(n),单次DFS遍历树。

  2. 应用拓展:此类问题常结合栈处理括号序列与树结构,需灵活转化模型。

转自:【CSP-S 2019】括号树(洛谷P5658)解题报告:栈+DFS+异或优化详解

点赞
收藏
评论区
推荐文章
徐小夕 徐小夕
4年前
JavaScript 中的二叉树以及二叉搜索树的实现及应用
接下来让我们一起来探讨js数据结构中的树。这里的树类比现实生活中的树,有树干,树枝,在程序中树是一种数据结构,对于存储需要快速查找的数据非有用,它是一种分层数据的抽象模型。一个树结构包含一系列存在父子关系的节点。每个节点都有一个父节点以及零个或多个子节点。如下所以为一个树结构:)(https://imghelloworld.osscnbe
Stella981 Stella981
3年前
LeetCode(98): 验证二叉搜索树
Medium!题目描述:给定一个二叉树,判断其是否是一个有效的二叉搜索树。一个二叉搜索树具有如下特征:节点的左子树只包含小于当前节点的数。节点的右子树只包含大于当前节点的数。所有左子树和右子树自身必须也是二叉搜索树。示例 1:输入:2/\
Wesley13 Wesley13
3年前
PHP数据结构与算法:树
一、概念树(Tree)是一种抽象数据类型(ADT)或是实作这种抽象数据类型的数据结构,用来模拟具有树状结构性质的数据集合。它是由n(n1)个有限节点组成一个具有层次关系的集合。看起来向一颗根朝上叶朝下的的倒挂树。每个节点有零个或多个子节点没有父节点的节点称为根节点每一个非根节点有且只有一个父节点除根
Wesley13 Wesley13
3年前
C语言递归之二叉树的最小深度
https://www.cnblogs.com/shichampion/p/12262678.html题目描述给定一个二叉树,找出其最小深度。最小深度是从根节点到最近叶子节点的最短路径上的节点数量。说明: 叶子节点是指没有子节点的节点。示例输入:3,9,20,null,null,15,7
Wesley13 Wesley13
3年前
B
BTreeBTree又叫做B树,和平衡二叉树不同的地方在于B树是多叉树(平衡多路查找树),Oracle和MongoDB的索引技术就是基于B树的数据结构,B树也可以看作是对23查找树的一种扩展。一个m阶的BTree有以下性质1.每个节点最多有m个子节点;2.每个非叶子节点(根节点除外)至少含有m/2个子节点;3.
Stella981 Stella981
3年前
LeetCode112
非商业,LeetCode链接附上:https://leetcodecn.com/problems/pathsum/进入正题。题目:给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。说明: 叶子节点是指没有子节点的节点。示例:给定如下二叉树,以及目标和
小万哥 小万哥
1年前
DOM 节点遍历:掌握遍历 XML文档结构和内容的技巧
遍历是指通过或遍历节点树遍历节点树通常,您想要循环一个XML文档,例如:当您想要提取每个元素的值时。这被称为"遍历节点树"。下面的示例循环遍历所有的子节点,并显示它们的名称和值:htmlvarx,i,xmlDoc;vartxt"";vartext"""E
贾蔷 贾蔷
7小时前
【蓝桥杯2015省赛解析】生命之树(洛谷P8625):树形DP解题全攻略
一、题目解读“生命之树”是一道经典的树形结构问题,要求计算一棵带权树中,以某个节点为根的最大子树权值和。题目输入为n个节点及边信息,每个节点有权值wi,需找到所有节点中,子树权值和最大的节点,并输出其值。核心挑战在于如何处理树形结构的递归关系,并高效聚合子
深度学习 深度学习
7小时前
洛谷1111题解:基于Kruskal算法与并查集的最小生成树实现
一、题目解读洛谷1111题是一道经典的图论问题,要求构建一个无向图的最小生成树,并输出其最大边权值。题目核心在于通过给定的边集合,找到连接所有节点的最小权值子集,同时保证无环。这通常涉及最小生成树算法(如Kruskal)的应用,需要高效处理边权重与节点连通
贾蔷 贾蔷
7小时前
牛客13279题解:利用递归与深度优先搜索计算树的最大高度(附完整代码)
一、题目解读牛客13279题要求计算给定树的最大高度。题目输入一棵以邻接表形式表示的树(节点从0开始编号),需要输出从根节点到最深叶节点的最长路径长度。树的结构由n个节点和n1条边构成,保证为连通无环图。理解题目核心在于准确获取树的拓扑关系,并设计算法遍历