1. 程式人生 > 實用技巧 >【洛谷 5658】括號樹

【洛谷 5658】括號樹

題目背景

本題中合法括號串的定義如下:

  1. ()是合法括號串。
  2. 如果A是合法括號串,則(A)是合法括號串。
  3. 如果AB是合法括號串,則AB是合法括號串。

本題中子串與不同的子串的定義如下:

  1. 字串S的子串是S中連續的任意個字元組成的字串。S的子串可用起始位置ll與終止位置rr來表示,記為S (l, r)S(l,r)(1 \leq l \leq r \leq |S |1lrS∣,|S |S∣表示 S 的長度)。
  2. S的兩個子串視作不同當且僅當它們在S中的位置不同,即ll不同或rr不同。

題目描述

一個大小為nn的樹包含nn個結點和n − 1n1條邊,每條邊連線兩個結點,且任意兩個結點間有且僅有一條簡單路徑互相可達。

小 Q 是一個充滿好奇心的小朋友,有一天他在上學的路上碰見了一個大小為nn的樹,樹上結點從11∼nn編號,11號結點為樹的根。除11號結點外,每個結點有一個父親結點,uu(2 \leq u \leq n2un)號結點的父親為f_ufu1 ≤ f_u < u1fu<u)號結點。

小 Q 發現這個樹的每個結點上恰有一個括號,可能是()。小 Q 定義s_isi為:將根結點到ii號結點的簡單路徑上的括號,按結點經過順序依次排列組成的字串。

顯然s_isi是個括號串,但不一定是合法括號串,因此現在小 Q 想對所有的ii(1\leq i\leq n1in)求出,s_isi中有多少個互不相同的子串是合法括號串。

這個問題難倒了小 Q,他只好向你求助。設s_isi共有k_iki個不同子串是合法括號串, 你只需要告訴小 Q 所有i \times k_ii×ki的異或和,即:

(1 \times k_1)\ \text{xor}\ (2 \times k_2)\ \text{xor}\ (3 \times k_3)\ \text{xor}\ \cdots\ \text{xor}\ (n \times k_n)(1×k1)xor(2×k2)xor(3×k3)xorxor(n×kn)

其中xorxor是位異或運算。

輸入格式

第一行一個整數nn,表示樹的大小。

第二行一個長為nn的由()

組成的括號串,第ii個括號表示ii號結點上的括號。

第三行包含n − 1n1個整數,第ii(1 \leq i \lt n1i<n)個整數表示i + 1i+1號結點的父親編號f_{i+1}fi+1

輸出格式

僅一行一個整數表示答案。

輸入輸出樣例

輸入 #1
5
(()()
1 1 2 2
輸出 #1
6

說明/提示

【樣例解釋1】

樹的形態如下圖:

將根到 1 號結點的簡單路徑上的括號,按經過順序排列所組成的字串為(,子串是合法括號串的個數為00。

將根到 2 號結點的字串為((,子串是合法括號串的個數為00。

將根到 3 號結點的字串為(),子串是合法括號串的個數為11。

將根到 4 號結點的字串為(((,子串是合法括號串的個數為00。

將根到 5 號結點的字串為((),子串是合法括號串的個數為11。

【資料範圍】

題解:去年0分題,哎////鏈分如下~

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N=500003;
char tree[N];
int f[N];
ll sum[N],lst[N]; 
int n,t;
ll ans;
int main(){
    freopen("5658.in","r",stdin);
    freopen("5658.out","w",stdout);
    scanf("%d",&n);
    scanf("%s",tree+1);
    //for(int i=1;i<=n;i++) cin>>tree[i];
    for(int i=2;i<=n;i++) scanf("%d",&f[i]);
    stack <int> s;
    for(int i=1;i<=n;i++){ 
        if(tree[i]==')'){   
            if(s.empty()) continue;
            t=s.top();
            lst[i]=lst[t-1]+1;
            s.pop();
        }
        else s.push(i);     
    }
    for(int i=1;i<=n;i++){
        sum[i]=sum[i-1]+lst[i];
        ans=ans^(ll)((ll)i*sum[i]);
    } 
    cout<<ans<<endl;
    return 0;
}