首先看到这个题
先看数据分布
可以发现,存在55分的链的处理
简易推理可知存在两种情况
- 合法括号字串+合法合法括号字串,如 ( )( )( )( )
- 合法括号字串里有合法括号字串,如 ( ( ) )
- ( + 一大堆无关的玩意 + )
显然可以考虑用栈来解决这个问题
步骤为:
令SUMp为 以p节点为结尾的在根节点到p节点的路径上的单次匹配
- 当入栈的为(时,直接把下标存入栈中
2.当入栈的为)时,必须与栈中(的位置匹配,又因为可以继承(之前的答案,所以操作就很明显了
SUMp=SUM.(Q.TOP()-1)+1;
Q.POP();
然后就ok了
综上,期望得分55,时间复杂度O(n)
做到这里,后面45分就非常好拿了
考虑将从根节点出发的到每一个节点变化为一条链,然后在这条链上计算答案
又因为答案具有重复计算的特征,故可以考虑一种以O(n)时间复杂度为基础的算法 -----大法师(dfs)
然后关于如何维护每一条链上的栈
再每一次dfs时进行一次回溯就可以解决这个问题
综上,期望得分100,时间复杂度O(n)
#include<bits/stdc++.h>
using namespace std;
long long n,sy,sum[500005],ans=0,h[500005],tot=0,fa[500005];
char kh[500005];
stack<long long>q;
struct node{
int next,to,from;
}e[500005];
void add(int x,int y){
tot++;
e[tot].next=h[x];
e[tot].to=y;
e[tot].from=x;
h[x]=tot;
}
int dfs(int now){
if(kh[now]=='('){
q.push(now);
for(int i=h[now];i;i=e[i].next)dfs(e[i].to);
q.pop();
}
else if(!q.empty()){
//sum[now]=1+sum[q.top()-1];
sum[now]=1+sum[fa[q.top()]];
long long zhongzan=q.top();
q.pop();
for(int i=h[now];i;i=e[i].next)dfs(e[i].to);
q.push(zhongzan);
}
else{
for(int i=h[now];i;i=e[i].next)dfs(e[i].to);
}
}
int as(int now){
for(int i=h[now];i;i=e[i].next){
sum[e[i].to]+=sum[now];
as(e[i].to);
}
ans=ans^(now*sum[now]);
}
int main(){
//freopen("testdata (1).in","r",stdin);
cin>>n;memset(sum,0,sizeof(sum));
for(long long i=1;i<=n;i++)cin>>kh[i];
for(long long i=1;i<n;i++){
cin>>sy;
add(sy,i+1);
fa[i+1]=sy;
}
dfs(1);
as(1);
cout<<ans<<endl;
}