[CSP-S]括号树

题目

题解

本人语言能力有限,看代码可能更好理解,以下题解可跳过
此题就是一系列恶心人的情况,你一一讨论出来就可以过了。
PS:我的方法好像跟其他做法不太一样,各位请选择观看
一般思路肯定就是一直搜下去。
本人认为本题的最大难点就是它成功地匹配了一个,对总和ki的贡献值。
首先看这一情况(()),这我们只能看作一个整体,因为在后面再加入一个(),它也不能用内部的括号
新增的合格括号则对答案的贡献与之前连续整体的数量有关,这个不好描述
看图(()))(()()(此时如果多加一个)则对总和ki的贡献值是3,算上它本身,还有前面两个括号组可以与它组合合法括号串
而最前面的一堆合法括号串被隔开,显然不能够对答案进行贡献。
确实很难描述,建议手动推一下
我们拿pre数组表示离i结点最近是且未被匹配的祖先(或者它本身)
num[i]表示遍历到i,当前连续整体的个数
sum[i]则统计当前结点答案
如果当前结点是(,sum就是父亲结点的值
如果之前并不是整体,那么这个时候前面暂时就没有连续的点。
如果是整体,那么num应该加1
如果当前结点是)如果前面没有左括号,则sum,与num承接父亲
如果有,那么sum就是要加上1,并且连续整体的数量
同时pre,num数组需特殊更新(主要是实在描述不出来了,我太逊了)
至于判断是否判断整体,我们用了flag。
整体是个bfs。
我的代码也是被很多大佬吊打

代码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<queue>
#include<set>
#define N 500005
using namespace std;
struct node{
	int u,fg;
	node(){};
	node(int U,int F){
		u = U,fg = F;
	}
};
int n,fa[N],pre[N],num[N];
long long ans,sum[N];
char c[N];
vector<int>G[N];
void bfs(){
	queue<node>Q;
	Q.push(node(1,0));
	while (!Q.empty()){
		int u = Q.front().u,flag = Q.front().fg;
		Q.pop();
		for (int i = 0;i < G[u].size();i ++){
			int v = G[u][i];	
			bool flag1 = 0;
			if (c[v] == '('){
				sum[v] = sum[u];
				pre[v] = v;
				if (!flag || c[u] == '(')
					num[v] = 0;
				else if (flag)
					num[v] = num[u] + 1;
			}
			else {
				if(!pre[u]){
					sum[v] = sum[u];
					num[v] = num[u];
				}
				else {
					sum[v] = sum[u] + 1 + num[pre[u]];
					pre[v] = pre[fa[pre[u]]];
					flag1 = 1;
					num[v] = num[pre[u]];
				}
			}
			ans = ans ^ (sum[v] * v);
			Q.push(node(v,flag1));
		}
	}
}
int main(){
	scanf ("%d\n",&n);
	for (int i = 1;i <= n;i ++)
		scanf ("%c",&c[i]);
	for (int i = 2;i <= n;i ++){
		scanf ("%d",&fa[i]);
		G[fa[i]].push_back(i);
	}
	if (c[1] == '(')
		pre[1] = 1;
	bfs();
	printf("%lld\n",ans);
}
}

结语

自己能力不强,考场做的题现在都推不出来。总之一句话:我菜炸了。
自己真的是个菜逼,明明很显然的代码却是打得很复杂。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值