洛谷 P5658 [CSP-S2019] 括号树

洛谷 P5658 [CSP-S2019] 括号树

题意

给定一棵树,每个点有一个括号 ()

定义 si 表示 根节点到 i 每个点的括号组成的序列。

求每个 si 中合法括号子串的个数 fi

思路

定义 gi 表示 si 中以 i 结尾的合法括号子串的个数。

fi=ffai+gi,求出 gi 即可。

i 为左括号,gi=0

i 为右括号,

若没有左括号和它匹配,gi=0

若有左括号和它匹配,设为第 j 个,gi=gfaj+1

即这一段匹配的括号接在上一段后面,又多出来了一个。

如图,黑色表示上一段的 g,红色表示这一段匹配的括号,绿色表示这一段的 g

由于两个合法子串拼接后仍为合法子串,所以 [8,9] 可以单独,也可以和 [6,4],[6,1] 拼接,这样就是 g6+1

代码

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 5e5 + 5;
int n, fa[N], stk[N], top; 
char s[N];
ll ans, g[N], f[N];
vector <int> E[N];
void dfs(int x) {
	int flg = 0;
	if (s[x] == '(') stk[++ top] = x;
	else if (top) g[x] = g[fa[stk[top]]] + 1, flg = stk[top --]; 
	f[x] = f[fa[x]] + g[x];
	for (auto y : E[x]) dfs(y);
	if (s[x] == '(') top --;
	else if (flg) stk[++ top] = flg;
}
int main() {
	scanf("%d", &n);
	scanf("%s", s + 1);
	for (int i = 2; i <= n; i ++) 
		scanf("%d", &fa[i]), 
		E[fa[i]].push_back(i);
	dfs(1);
	for (int i = 1; i <= n; i ++) 
		ans ^= 1ll * i * f[i];
	printf("%lld\n", ans);
	return 0;
}
posted @   maniubi  阅读(25)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
历史上的今天:
2022-09-06 CF1717A题解
点击右上角即可分享
微信分享提示