【CSP2019 D1T2】【括号树】
阅读原文时间:2023年07月10日阅读:1

题面

不再多说,想必大家都看过这个题

思路

我们可以手推几个满足条件的字符串

我们发现在这些字符串里

每个)都与离它最近的(的匹配

所以我们维护树上每个节点到根节点中没用使用过的(的位置(nl[n]) h[i]表示以i的结尾的满足条件的串的个数

    nl[n] = nl[fa[n]];
    if(value[n] == 1)
    nl[n] = n;
    else
    {
        if(nl[n] != 0)
        {
        ll f = fa[nl[n]];
        nl[n] = nl[f];
    h[n] = 1 + h[f];//把离)最近的(使用
        }
    }

最后因为是字串 所以需要h[i]前缀和

(注意\(1<=f_u<u\))

代码

#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;
const ll M = 500015;
struct edge{
    ll to,next;
}QWQ[M];
ll head[M],n,fa[M],value[M],h[M],nl[M],ans;
void merge(ll x,ll y)
{
    QWQ[ ++QWQ[0].to ].to = x;
    QWQ[ QWQ[0].to ].next = head[y];
    head[y] = QWQ[0].to;
}
void dfs(ll n)
{
    nl[n] = nl[fa[n]];
    if(value[n] == 1)
    nl[n] = n;
    else
    {
        if(nl[n] != 0)
        {
        ll f = fa[nl[n]];
        nl[n] = nl[f];
        h[n] = 1 + h[f];
        }
    }
    for(ll i = head[n];i;i = QWQ[i].next)
    dfs(QWQ[i].to);
}
int main()
{
    scanf("%lld",&n);
    char c;
    for(ll i = 1;i <= n;i++)
    {
        c = getchar();
        while(c != '('&&c != ')')
        c = getchar();
        if(c == '(')
        value[i] = 1;
        if(c == ')')
        value[i] = 2;
    }
    for(ll i = 2;i <= n;i++)
    {
        scanf("%lld",&fa[i]);
        merge(i,fa[i]);
    }
    dfs(1);
    ans = h[1];
    for(ll i = 2;i <= n;i++)
    {
        ll j = i;
        h[i] += h[fa[j]];
        ans ^= i * h[i];
    }
    cout<<ans;
}

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章