Description
Solution
树形 dp。
合法括号串本质上有两个
- 单独串,如
()
。单独串仅有一队括号构成,如()()
有两个单独串。 - 嵌套串,如
(()())
。嵌套串的定义大于单独串,如(()())
为一个嵌套串,且它的子串中没有单独串。
性质 1:单独串和嵌套串可以与其他的合法括号串匹配。
性质 2:如果 有(
,那么等待之后的 )
。如果 )
前没有 )
与它匹配,则没有包括它的合法括号串。
有了上述性质后,状态与转移方程也呼之欲出了。
为从根节点到 的路径上的合法括号子串数。
为在
的上方,第一个等待匹配的 (
的结点。
为从
到根节点的路径上,连续的单独串与嵌套串的个数。如 ()(()())()
依次为 ()
、(()())
、()
。
状态转移见代码。
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 5;
char s[N];
ll fa[N], f[N], lst[N], cnt[N], n, ans;
int main(){
scanf("%lld%s", &n, s + 1);
for (int i = 2; i <= n; i++) scanf("%lld", &fa[i]);
for (int x = 1; x <= n; x++) {
f[x] = f[fa[x]], lst[x] = lst[fa[x]];
if (s[x] == '(') lst[x] = x;
else if (lst[x]) cnt[x] = cnt[fa[lst[x]]] + 1, lst[x] = lst[fa[lst[x]]], f[x] = f[x] + cnt[x];
ans ^= x * f[x];
}
printf("%lld\n", ans);
return 0;
}