P5658 [CSP-S2019] 括号树

对于特殊性质fi=i-1,原图是一条链,注意到当前节点是‘ (’不会产生贡献,‘)’才会产生,那么思考怎么的计算这个贡献。

()()():每个位置贡献是0,1,0,2,0,3。答案统计出来就是说0,1,1,3,3,6。

())():贡献是0,1,0,0,1。答案是0,1,1,1,2。

()(()):0,1,0,0,1,2.      0,1,1,1,2,4。

右括号需要匹配左括号,所以将左括号的位置加入一个栈中,匹配成功就弹出,每个右括号的贡献就是他所匹配的左括号的前一个右括号的贡献值+1,这样对于链的情况就解决了。

树上也可以用同样的思路,注意递归会对栈有修改,所以回溯时要复原。

 1 #include <bits/stdc++.h>
 2 #define inf 0x3f3f3f3f
 3 #define ll long long
 4 #define maxn 500005
 5 //#define loveGsy
 6 using namespace std;
 7 int n;
 8 char c[maxn];
 9 int head[maxn], nxt[maxn], to[maxn], cnt, fa[maxn];
10 ll lst[maxn], sum[maxn], ans;
11 int s[maxn], top;
12 
13 void add(int u, int v) {
14     nxt[++cnt] = head[u];
15     head[u] = cnt;
16     to[cnt] = v;
17 }
18 
19 void dfs(int x) {
20     int tmp = 0;
21     if (c[x] == ')') {
22         if (top) {
23             tmp = s[top];
24             lst[x] = lst[fa[tmp]] + 1;
25             --top;
26         }
27     }
28     else if (c[x] == '(') s[++top] = x;
29     sum[x] = sum[fa[x]] + lst[x];
30     for (int i = head[x]; i; i = nxt[i]) dfs(to[i]);
31     if (tmp != 0) s[++top] = tmp;
32     else if (top) --top; 
33     //回溯复原 
34 }
35 
36 int main() {
37 #ifdef loveGsy
38     freopen("a.in", "r", stdin);
39     freopen("a.out", "w", stdout);
40 #endif
41     scanf("%d", &n);
42     scanf("%s", c + 1);
43     for (int i = 2; i <= n; i++) {
44         int f;
45         scanf("%d", &f);
46         add(f, i);
47         fa[i] = f;
48     }
49     dfs(1);
50     for (int i = 1; i <= n; i++) 
51         ans ^= sum[i] * (ll)i;
52     printf("%lld", ans);
53     return 0;
54 }

 

posted @ 2022-07-28 10:05  YHXo  阅读(48)  评论(0编辑  收藏  举报