题目分析
题目分析
- 这一道题我一开始看觉得应该是DP。
- 对于点i的答案,显然是它的父亲的答案加上以它为结尾的合法括号串的个数。
- 如何求以i为结尾的合法括号串的个数呢?
- 我们设
f[i][j]代表的是以
i点为结尾,目前有
j个左括号没有配对的方案数。
- 显然如果
i是左括号,那么
f[i][j]=f[fa[i]][j−1],否则
f[i][j]=f[fa[i]][j+1]。其中
fa[i]为
i的父亲。
- 这样我们便能发现,其实转移就是整个区间的左移或者右移。我们可以设一个指针,如果该点为左括号,我们就把指针往左移一格,否则就往右移一格。
- 这样时间复杂度就可以保证在
O(n)范围以内。
注意
- 如果当前点为左括号,还要注意
f[i][1]++。
代码
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=5e5+100;
struct node{
int x,y,next;
}a[2*N];int len,last[N];
int n,fa[N],f[3*N];char s[N];
void ins(int x,int y){
a[++len].x=x;a[len].y=y;
a[len].next=last[x];last[x]=len;
}
ll Sum[N];
void dfs(int x,int st){
int t;
if(s[x]=='('){
t=f[st];
f[st]=0;f[st+1]++;
}
Sum[x]=f[st];
for(int k=last[x];k;k=a[k].next){
int y=a[k].y;
if(s[y]=='(') dfs(y,st-1);
else dfs(y,st+1);
}
if(s[x]=='(') f[st]=t,f[st+1]--;
}
int main()
{
freopen("brackets.in","r",stdin);
freopen("brackets.out","w",stdout);
scanf("%d",&n);
scanf("%s",s+1);
for(int i=2;i<=n;i++){
scanf("%d",&fa[i]);
ins(fa[i],i);
}
dfs(1,n);
ll Ans=0;
for(int i=1;i<=n;i++){
Sum[i]=Sum[fa[i]]+Sum[i];
ll t=(ll)Sum[i]*i;
Ans=Ans^t;
}
printf("%lld\n",Ans);
return 0;
}