括号树 noip(csp??) 2019 洛谷 P5658

洛谷AC通道

本题,题目长,但是实际想起来十分简单。

首先,对于树上的每一个后括号,我们很容易知道,他的贡献值等于上一个后括号的贡献值 + 1。(当然,前提是要有人跟他匹配,毕竟题目中要求了,是不同的子串。)

那么,如何记录是否有人跟他匹配??  也很好想。。。  用一个栈来维护(同时也方便我们记录上一个后括号所在的位置。)

那么,求总贡献值呢??  更好办了。  直接等于他爸爸 + 他自己的呗!!

结束了~~~

#include <bits/stdc++.h>
using namespace std;
#define N 600010
#define ll long long

inline ll read(){
    ll x = 0, s = 1;
    char c = getchar();
    while(!isdigit(c)){
        if(c == '-')s = -1;
        c = getchar();
    }
    while(isdigit(c)){
        x = (x << 1) + (x << 3) + (c ^ '0');
        c = getchar();
    }
    return x * s; 
}

int fa[N];
ll sum[N], lst[N];

struct node{
    int v, next;
} t[N];
int f[N];
int a[N];
char c[N];

int bian = 0;
inline void add(int u, int v){
    t[++bian] = (node){v, f[u]};
    f[u] = bian;
    return ;
}

int stac[N], top = 0;
void dfs(int now){
    int temp = 0;;
    if(c[now] == '('){
        stac[++top] = now;
    }
    else if(c[now] == ')'){
        if(top){
            temp = stac[top];
            lst[now] = lst[fa[temp]] + 1;
            top--;
        }
    }
    sum[now] = sum[fa[now]] + lst[now];
    for(int i = f[now]; i; i = t[i].next){
        int v = t[i].v;
        dfs(v);
    }
    if(temp != 0) stac[++top] = temp;
    else if(top) top--;
    return ;
}

int main(){
    int n = read();
    scanf("%s", c + 1);
    for(int i = 2;i <= n; i++){
        int x = read();
        add(x, i);
        fa[i] = x;
    }
    dfs(1);
    ll ans = 0;
    for(ll i = 1;i <= n; i++)
        ans ^= i * sum[i];
    printf("%lld
", ans);
    return 0;
}
原文地址:https://www.cnblogs.com/wondering-world/p/12945418.html