洛谷 P5658 括号树 题解
简要题意:
求出以从每个节点到根形成的括号序列的合法对数。
算法一
观察到 \(n \leq 8\) ,所以我们可以用 纯粹的暴力 。
用 \(O(n)\) 时间得出当前节点到根的字符串。
然后 \(O(n^2)\) 枚举子串。
再用 \(O(n)\) 暴力判断(用栈)。
时间复杂度: \(O(n^5)\).
实际得分: \(10pts\).
优化一
用 \(s_i\) 表示 \(i\) 号节点对应的括号。
用 \(h_i\) 表示当前节点到根的字符串。
用 \(fa_i\) 表示当前节点的父亲编号。
则:
\]
由此,\(O(1)\) 推出字符串。
然后 \(O(n^2)\) 枚举子串,\(O(n)\) 验证。
时间复杂度: \(O(n^4)\)
实际得分: \(10pts\).
优化二
同样 \(O(1)\) 推出字符串。
下面,我们用 \(f_i\) 表示从第 \(i\) 号节点到根形成的括号序列的合法对数。
那么,显然存在:
\(f_i \geq f_{fa_i}\)
也就是说,我们只需要考虑以 \(i\) 号节点结尾的子串的贡献。
这样,我们枚举子串的时间复杂度降为 \(O(n)\),判断降为 \(O(n)\).
总时间复杂度: \(O(n^3)\)
实际得分:\(20pts\)
优化三
显然,我们需要摆脱枚举子串,而用另一些东西直接维护。
\begin{cases}
h_{fa_i},s_i = \text{(} \\
h_{fa_{g_i}}, s_i = \text{)} \\
\end{cases}
\]
其中, \(g_i\) 表示从当前节点开始,到根的路径上第一个(从下往上数)未匹配的左括号。
如果 \(s_i = \text{(}\) ,显然以当前节点结尾没有合法子串。
如果 \(s_i = \text{)}\) , 则找到它可以匹配的第一个左括号,然后记录那个左括号父亲的值(即前面的值)即可。
那么,\(g_i\) 如何维护呢?
\begin{cases}
i , s_i = \text{(} \\
g_{fa_i} , s_i = \text{)} \\
\end{cases}
\]
这也是显然的。
那么,我们可以做到 \(O(n)\) 时间维护这所有的东西。
总时间复杂度: \(O(n)\).
实际得分: \(100pts\).
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+1;
typedef long long ll;
inline int read(){char ch=getchar();int f=1;while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
int x=0;while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}
char s[N];
int n; ll ans;
ll f[N],g[N],fa[N];
vector<int>G[N];
// f[i] 为 当前节点的贡献值
// g[i] 为 从当前节点起,第一个没匹配的左括号的编号
inline void dfs(int dep) {
g[dep]=g[fa[dep]];
if(s[dep]=='(') g[dep]=dep;
else if(g[dep]) f[dep]=f[fa[g[dep]]]+1,g[dep]=g[fa[g[dep]]]; //维护
for(int i=0;i<G[dep].size();i++) dfs(G[dep][i]); //递归下去
}
int main(){
n=read(); scanf("%s",s+1); //一个技巧,让字符串下标从 1 开始
for(int i=2,t;i<=n;i++) {
t=read(); fa[i]=t;
G[t].push_back(i); //存儿子节点编号
} dfs(1);
ans=f[1]; for(int i=2;i<=n;i++)
f[i]+=f[fa[i]],ans^=(i*f[i]); //我们把父亲的值放到最后算,避免出错
printf("%lld\n",ans);
return 0;
}
洛谷 P5658 括号树 题解的更多相关文章
- 洛谷 P5658 括号树
\(50pts\) #include <cstdio> #include <cstring> #include <iostream> #include <al ...
- P5658 括号树
P5658 括号树 题解 太菜了啥都不会写只能水5分数据 啥都不会写只能翻题解 题解大大我错了 我们手动找一下规律 我们设 w[ i ] 为从根节点到结点 i 对答案的贡献,也就是走到结点 i ,合 ...
- 2021.08.09 P5658 括号树(树形结构)
2021.08.09 P5658 括号树(树形结构) [P5658 CSP-S2019] 括号树 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 题意: 太长,在链接中. 分析及代码 ...
- 【洛谷P3960】列队题解
[洛谷P3960]列队题解 题目链接 题意: Sylvia 是一个热爱学习的女孩子. 前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. Sylvia 所在的方阵中有 n×m ...
- 洛谷1087 FBI树 解题报告
洛谷1087 FBI树 本题地址:http://www.luogu.org/problem/show?pid=1087 题目描述 我们可以把由“0”和“1”组成的字符串分为三类:全“0”串称为B串,全 ...
- 洛谷P2832 行路难 分析+题解代码【玄学最短路】
洛谷P2832 行路难 分析+题解代码[玄学最短路] 题目背景: 小X来到了山区,领略山林之乐.在他乐以忘忧之时,他突然发现,开学迫在眉睫 题目描述: 山区有n座山.山之间有m条羊肠小道,每条连接两座 ...
- 洛谷P2312 解方程题解
洛谷P2312 解方程题解 题目描述 已知多项式方程: \[a_0+a_1x+a_2x^2+\cdots+a_nx^n=0\] 求这个方程在 \([1,m]\) 内的整数解(\(n\) 和 \(m\) ...
- 洛谷P1577 切绳子题解
洛谷P1577 切绳子题解 题目描述 有N条绳子,它们的长度分别为Li.如果从它们中切割出K条长度相同的 绳子,这K条绳子每条最长能有多长?答案保留到小数点后2位(直接舍掉2为后的小数). 输入输出格 ...
- 洛谷P2507 [SCOI2008]配对 题解(dp+贪心)
洛谷P2507 [SCOI2008]配对 题解(dp+贪心) 标签:题解 阅读体验:https://zybuluo.com/Junlier/note/1299251 链接题目地址:洛谷P2507 [S ...
随机推荐
- 借助mkcert签发本地证书
mkcert 是由 Filippo Valsorda 使用go语言开源的一款零配置搭建本地证书服务的工具,它可以兼容Window, Linux, macOS等多种开发平台,省去了我们自签本地证书的繁琐 ...
- GRE阅读
界面和托福差不多,就是反一反 GRE先读文章!因为出题顺序不一致.另外,不能跳读!!每一句都要读,即使不是观点. 考察能力: 1 三秒版本 边读边概括 解决前面的抗遗忘能力 2 句间关系 取同 取反 ...
- 用RecyclerView做一个小清新的Gallery效果 - Ryan Lee的博客
一.简介 RecyclerView现在已经是越来越强大,且不说已经被大家用到滚瓜烂熟的代替ListView的基础功能,现在RecyclerView还可以取代ViewPager实现Banner效果,当然 ...
- Python使用input方法输入字母显示NameError
如图,每次用input方法,输入数字正常,但是输入字母就会报错. 到网上查找资料之后,明白了原来在python2.7中应该用raw_input. 修改之后,代码就正常了.
- C++走向远洋——25(项目二,游戏类)
*/ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:game.cpp * 作者:常轩 * 微信公众号:Worldhe ...
- python爬虫之selenium+打码平台识别验证码
1.常用的打码平台:超级鹰.打码兔等 2.打码平台在识别图形验证码和点触验证码上比较好用 (1)12306点触验证码 from selenium import webdriver from selen ...
- Flutter Widgets 对话框-Dialog
注意:无特殊说明,Flutter版本及Dart版本如下: Flutter版本: 1.12.13+hotfix.5 Dart版本: 2.7.0 当应用程序进行重要操作时经常需要用户进行2次确认,以避免用 ...
- 重置gitlab管理员密码
gitlab web管理员登录密码忘记以后可以用如下方式修改密码(本演示系统为Linux-CentOS6.6): [root@localhost ~]# gitlab-rails console pr ...
- 面试题57-II.和为s的连续正数序列
面试题57-II.和为s的连续正数序列 1.题目 LeetCode-面试题57-II.和为s的连续正数序列 输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数 ...
- Python 存储数据到json文件
1 前言 很多程序都要求用户输入某种信息,程序一般将信息存储在列表和字典等数据结构中. 用户关闭程序时,就需要将信息进行保存,一种简单的方式是使用模块json来存储数据. 模块json让你能够将简单的 ...