题解 P5658 【括号树【民间数据】】

· · 题解

吐槽

看题解区,看到第三页

全是dfs

甚至还有的dalao开栈模拟搜索过程

我就想说:有这么难吗......(本次考试唯一一个AC的题

正题

首先这题的状态是很好设的。

对于第三个,说明一下:

比如对于这个括号序列:()()(),他其实是由三个()组成的,所以line[i] = 3

那么所有的变量转移如下

如果这个节点是 '(' ,那么f[i]line[i]直接继承父节点的,last[i]就是i

如果是 ')' ,但last[i]不存在,这个括号就无效了。

如果是 ')' ,且last[i]存在,那么就有以下转移:

然后去测大样例,然而大样例太臭了,会RE(或者是MLE?)。

这个时候各位大佬就选择了开栈模拟,这固然是一个好方法。

> $u$($2 \leq u \leq n$)号结点的父亲为 $f_u$($1 ≤ f_u < u$) 所以说,我们可以直接循环一遍...... # 代码 ```cpp #include<iostream> #include<cstdio> #include<cstring> using namespace std; inline int get() { int x = 0, f = 1; char c = getchar(); while(!isdigit(c)) { if(c == '-') f = -1; c = getchar(); } while(isdigit(c)) { x = x * 10 + c - '0'; c = getchar(); } return x * f; } const int N = 5e5 + 5; int n; struct Edge { //实测爆栈的铁证 int v, nxt; } edge[N << 1]; long long head[N], k = 0, fa[N], f[N], ans, last[N], line[N]; char w[N]; /* inline void addedge(int u, int v) { edge[++k].v = v; edge[k].nxt = head[u]; head[u] = k; } inline void insedge(int u, int v) { addedge(u, v), addedge(v, u); } */ inline void file() { freopen("brackets.in", "r", stdin); freopen("brackets.out", "w", stdout); } int main() { file(); n = get(); scanf("%s", w + 1); for(register int i = 2; i <= n; i++) { fa[i] = get(); //insedge(fa[i], i); } for(register int u = 1; u <= n; u++) { int fath = fa[u]; f[u] = f[fath], last[u] = last[fath]; if(w[u] == '(') last[u] = u; else if(w[u] == ')' && last[u]) { line[u] = line[fa[last[u]]] + 1; last[u] = last[fa[last[u]]]; f[u] += line[u]; } ans ^= u * f[u]; } printf("%lld", ans); return 0; } ```