CSP-S2 括号树

题目分析

在这里插入图片描述在这里插入图片描述

题目分析

  • 这一道题我一开始看觉得应该是DP。
  • 对于点i的答案,显然是它的父亲的答案加上以它为结尾的合法括号串的个数。
  • 如何求以i为结尾的合法括号串的个数呢?
  • 我们设 f [ i ] [ j ] f[i][j] 代表的是以 i i 点为结尾,目前有 j j 个左括号没有配对的方案数。
  • 显然如果 i i 是左括号,那么 f [ i ] [ j ] = f [ f a [ i ] ] [ j 1 ] f[i][j]=f[fa[i]][j-1] ,否则 f [ i ] [ j ] = f [ f a [ i ] ] [ j + 1 ] f[i][j]=f[fa[i]][j+1] 。其中 f a [ i ] fa[i] i i 的父亲。
  • 这样我们便能发现,其实转移就是整个区间的左移或者右移。我们可以设一个指针,如果该点为左括号,我们就把指针往左移一格,否则就往右移一格。
  • 这样时间复杂度就可以保证在 O ( n ) O(n) 范围以内。

注意

  • 如果当前点为左括号,还要注意 f [ i ] [ 1 ] + + 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;
}
发布了58 篇原创文章 · 获赞 12 · 访问量 8543

猜你喜欢

转载自blog.csdn.net/fengqiyuka/article/details/103254083