【洛谷 5658】括號樹
題目背景
本題中合法括號串的定義如下:
()
是合法括號串。- 如果
A
是合法括號串,則(A)
是合法括號串。 - 如果
A
,B
是合法括號串,則AB
是合法括號串。
本題中子串與不同的子串的定義如下:
- 字串
S
的子串是S
中連續的任意個字元組成的字串。S
的子串可用起始位置ll與終止位置rr來表示,記為S (l, r)S(l,r)(1 \leq l \leq r \leq |S |1≤l≤r≤∣S∣,|S |∣S∣表示 S 的長度)。 S
的兩個子串視作不同當且僅當它們在S
中的位置不同,即ll不同或rr不同。
題目描述
一個大小為nn的樹包含nn個結點和n − 1n−1條邊,每條邊連線兩個結點,且任意兩個結點間有且僅有一條簡單路徑互相可達。
小 Q 是一個充滿好奇心的小朋友,有一天他在上學的路上碰見了一個大小為nn的樹,樹上結點從11∼nn編號,11號結點為樹的根。除11號結點外,每個結點有一個父親結點,uu(2 \leq u \leq n2≤u≤n)號結點的父親為f_ufu(1 ≤ f_u < u1≤fu<u)號結點。
小 Q 發現這個樹的每個結點上恰有一個括號,可能是(
或)
。小 Q 定義s_isi為:將根結點到ii號結點的簡單路徑上的括號,按結點經過順序依次排列組成的字串。
顯然s_isi是個括號串,但不一定是合法括號串,因此現在小 Q 想對所有的ii(1\leq i\leq n1≤i≤n)求出,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)xor⋯xor(n×kn)
其中xorxor是位異或運算。
輸入格式
第一行一個整數nn,表示樹的大小。
第二行一個長為nn的由(
與)
第三行包含n − 1n−1個整數,第ii(1 \leq i \lt n1≤i<n)個整數表示i + 1i+1號結點的父親編號f_{i+1}fi+1。
輸出格式
僅一行一個整數表示答案。
輸入輸出樣例
輸入 #15 (()() 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; }