題目
題解
首先想到用單調棧將在樹上以i結尾的括號串記錄下來
然後進行分類討論
如果第i個字符是(,則i的答案就是i的父親的答案,是不變的
否則,這個有括號可能會對答案有貢獻:
如果在這之前,沒有其它的未匹配的右括號在(到i爲止)最近出現的左括號與i之間,那麼貢獻就會加1
舉例子:()() 如果i=4,那麼貢獻加一
否則:())) 如果i=4,那麼貢獻不變
但是還要考慮到像()()()這樣的情況,可以用前綴和解決
sum[i]表示到i爲止,有多少個括號()是串聯的
具體就是最近出現的左括號的序號的父親的前綴
如果匹配成功,記得將這個左括號消掉,則後面的右括號只能與更前面的左括號匹配
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;
#define ll long long
const int MAXN = 5e5 + 3;
int n , fa[MAXN];
vector<int>G[MAXN];
ll sum[MAXN] , ans[MAXN];
int sta[MAXN] , cnt;
int zf[MAXN] , cntz;
char a[MAXN];
void dfs( int x ){
for( int i = 0; i < G[x].size() ; i ++ ){
int v = G[x][i];
if( v == fa[x] ) continue;
ans[v] = ans[x];
if( a[v] == '(' ){
sta[++cnt] = v;
zf[++cntz] = v;
dfs( v );
sta[cnt--] = 0;zf[cntz--] = 0;
continue;
}
int y = zf[cntz];
bool fl = 0;
if( cntz > 0 )
ans[v] ++ , zf[cntz--]= 0 , fl = 1;
ans[v] += sum[fa[y]];
sum[v] = sum[fa[y]] + ( fl == 1 ? 1 : 0 );
sta[++cnt] = v;
dfs( v );
sum[v] = 0;
sta[cnt--] = 0;
if( fl )
zf[++cntz] = y;
}
}
int main()
{
scanf( "%d" , &n );
scanf( "%s" , a + 1 );
for( int i = 2 ; i <= n ; i++ ){
scanf( "%d" , &fa[i] );
G[fa[i]].push_back( i );
G[i].push_back( fa[i] );
}
sum[1] = ans[1] = 0;
sta[++cnt] = 1;
if( a[1] == '(' )
zf[++cntz] = 1;
dfs( 1 );
ll o = 1ll * ans[1] * 1;
for( int i = 2 ; i <= n ; i ++ )
o = o ^ ( 1ll * i * ans[i] );
printf( "%lld" , o );
return 0;
}