zoukankan      html  css  js  c++  java
  • 题解【洛谷P5658】[CSP-S 2019]括号树

    题面

    一道简单的栈与( ext{DP})的结合。

    首先介绍一下序列上的括号匹配问题,也就是此题在序列上的做法:

    • (dp_i) 表示以 (i) 结尾的合法的括号序列个数, (ss_i) 表示 (1)(i) 合法的括号序列字串个数。
    • 维护一个栈,左括号 ( ext{push}) 它的位置到栈中,右括号取出栈顶 (dp_i = dp_{sta_{top} - 1} + 1) , 然后 (ss_i=ss_{i-1}+dp_{i})
    • 答案即为 ((1 imes ss_1) oplus (2 imes ss_2) oplus dots oplus (n imes ss_n)) ,其中 (oplus) 为异或。

    考虑将这个问题转移到树上,只需要一个可回退的栈即可。

    这题真的不难,我考场上为什么没想出来啊

    我太菜了

    代码:

    #include <bits/stdc++.h>
    #define itn int
    #define gI gi
    #define int long long
    
    using namespace std;
    
    inline int gi()
    {
    	int f = 1, x = 0; char c = getchar();
    	while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();}
    	while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    	return f * x;
    }
    
    const int maxn = 500003;
    
    int n, ans, topp, ss[maxn], dp[maxn], sta[maxn], sum[maxn];
    int fa[maxn], tot, head[maxn], ver[maxn * 2], nxt[maxn * 2];
    char s[maxn];
    
    inline void add(int u, int v) {ver[++tot] = v, nxt[tot] = head[u], head[u] = tot;}
    
    void dfs(int u, int f)
    {
    	int fl = -1;
    	if (s[u] == '(') sta[++topp] = u; //左括号加入栈
    	else if (topp > 0) //右括号且栈中有对应的左括号
    	{
    		fl = sta[topp--]; //栈顶元素
    		dp[u] = dp[fa[fl]] + 1; //dp 数组记得 +1
    	}
    	sum[u] = sum[fa[u]] + dp[u]; //sum[u] 表示 1 到 u 的路径上合法括号序列的个数
    	for (int i = head[u]; i; i = nxt[i])
    	{
    		int v = ver[i];
    		if (v == f) continue;
    		dfs(v, u);
    	}
    	//将栈还原到访问节点 u 之前的状态
    	if (s[u] == '(') --topp; 
    	else if (fl != -1)
    	{
    		sta[++topp] = fl;
    	}
    }
    
    signed main()
    {
    	//freopen(".in", "r", stdin);
    	//freopen(".out", "w", stdout);
    	n = gi();
    	scanf("%s", s + 1);
    	bool fl = true;
    	for (int i = 2; i <= n; i+=1) 
    	{
    		fa[i] = gi();
    		if (fa[i] != i - 1) fl = false;
    		add(fa[i], i), add(i, fa[i]);
    	}
    	if (fl) //序列上的做法
    	{
    		for (int i = 1; i <= n; i+=1)
    		{
    			if (s[i] == '(') sta[++topp] = i;
    			else if (topp) dp[i] = dp[sta[topp--] - 1] + 1;
    			ss[i] = ss[i - 1] + dp[i];
    			ans ^= (i * ss[i]); 
    		}
    		printf("%lld
    ", ans);
    		return 0;
    	}
    	dfs(1, 0);
    	for (int i = 1; i <= n; i+=1) ans ^= (i * sum[i]);
    	printf("%lld
    ", ans);
    	return 0;
    }
    
  • 相关阅读:
    虚拟机Linux5下安装MyEclipse2014的步骤
    鉴赏
    Linux环境下安装WebStorm
    Bootstrap模态框
    AngularJs
    按钮颜色
    虚拟机里的weblogic之后怎样进入
    搭建GlusterFS文件系统
    邮件服务器fixpost服务(1)
    unbound域名解析
  • 原文地址:https://www.cnblogs.com/xsl19/p/12283223.html
Copyright © 2011-2022 走看看