题目:括号树(DP)

题目

思路

定义\(dp_i\)为从i号节点从上的()()()()····的长度
之后在定义\(sum_i\)为i号节点的答案
如果当前这个点不与任何节点匹配
那么这个点的sum值就是这个点父亲sum值就行了
如果不是呢
首先我们知道当前这个点与另一个点匹配
所有首先sum++
在考虑当前这个点最长的匹配
就是用这个点的父亲去考虑
考虑父亲是左括号或者右括号去转移就行了
用一个stack来维护就行了

代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<stack>
#include<vector>
using namespace std;
struct node
{
	int u;
	char c;
};
long long ans;
long long n;
long long summ[500005];
long long dp[500005];
int lena;
int faa[500005];
bool vis[500005];
char a[500005];
vector<int> g[500005];
stack<node> s;
void dfs(int u,int fa)
{
	faa[u]=fa;
	bool f=0;
	node t;
	if(!s.empty())	
	{
		if(a[u]==')'&&s.top().c=='(')
		{
			f=1;
			t=s.top();
			if(a[fa]=='(')
			{
				summ[u]=summ[fa]+1;
				dp[u]=dp[faa[fa]]+1;
				summ[u]+=dp[faa[fa]];	
			}
			else
			{
				summ[u]=summ[fa]+1;
				dp[u]=dp[faa[s.top().u]]+1;
				summ[u]+=dp[faa[s.top().u]];
			}
			s.pop();
		}
		else
		{
			summ[u]=summ[fa];
			node t1;
			t1.u=u;
			t1.c=a[u];
			s.push(t1);		
		}
	}
	else
	{
		summ[u]=summ[fa];
		node t1;
		t1.u=u;
		t1.c=a[u];
		s.push(t1);		
	}
	for(int i=0;i<g[u].size();i++)
	{
		int v=g[u][i];
		if(v!=fa)
		{
			dfs(v,u);	
		}
	}
	if(f)
	{
		s.push(t);
	}
	else
	{
		s.pop();
	}
	ans^=(1ll*u*summ[u]);
}
int main()
{
	freopen("brackets.in","r",stdin);
	freopen("brackets.out","w",stdout);
	scanf("%lld",&n);
	scanf("%s",a);
	lena=strlen(a);
	for(int i=lena;i>=1;i--)
		a[i]=a[i-1];
	for(int i=2,u;i<=n;i++)
	{
		scanf("%d",&u);
		g[u].push_back(i);
	}
	dfs(1,0);
	printf("%lld",ans);
	return 0;
}

posted @ 2019-11-18 16:27  loney_s  阅读(244)  评论(0)    收藏  举报