zoukankan      html  css  js  c++  java
  • Luogu P5658 括号树|搜索+递推

    CSP2019 S组D1T2

    题目链接

    题目大意:一棵树上每个节点有(或),根到每个节点的路径可形成一括号串,求根到每个节点形成的括号串的合法括号字串个数,取异或和。

    解析:该题为CSP2019提高组容易拿分的一道。选择写链是个不错选择(然后我就这里打挂了 70pts),正解其实在考场上也能想出。

    子串说明要连续,而我们接好一个括号后它显然可以接上前面连续的括号序列。

    即:设一个节点(x)的答案为(ans_x),设此次接的左括号位置(y),则(ans_x+=ans_y+1)(因为自己单独也算一个)。而一个节点的父亲节点的答案,也会在该节点中原封不动的展现,故应加上节点的所有父亲节点之答案。

    我们采用(dfs)算法遍历整棵树,遇到节点为左括号进栈,否则在栈中匹配一个还没有匹配的左括号,成功匹配,则按上面累加答案。

    这里有一个问题,即从(dfs)退出时,我们在这里的东西需销毁,这同时牵涉到上面左括号的匹配。因此,这里采用(vis)来维护上述。若该节点为左括号,则结束搜索时将该节点退出栈。否则取消该节点匹配的左括号的已匹配状态,然后退出搜索。

    具体解析见代码。

    #include<bits/stdc++.h>
    using namespace std;
    int cc,to[600000],net[600000],fr[600000],fa[600000],zhan[600000],t,n,nt[600000];
    long long s[600000];
    char ch[600000];string st;bool vis[600000];
    void addedge(int u,int v)
    {
    	cc++;
    	to[cc]=v;net[cc]=fr[u];fr[u]=cc;
    }
    void dfs1(int x)//匹配括号
    {
    	if (ch[x]=='(') 
    	{
    		zhan[++t]=x;
    	}//压栈
    	else
    	{
    		nt[x]=t;//备份,不与全局冲突,后边操作用
    		while (vis[zhan[nt[x]]]&&nt[x])
    		{
    			nt[x]--;
    		}
    		if (nt[x])
    		{
    			vis[zhan[nt[x]]]=true;
    			s[x]=s[x]+1+s[fa[zhan[nt[x]]]];
    		}//匹配左括号
    	}
    	for (int i=fr[x];i;i=net[i])
    	{
    		dfs1(to[i]);
    	}//往下继续找
    	if (ch[x]=='(')
    		 t--;
    	else vis[zhan[nt[x]]]=false;//还原数组
    }
    void dfs2(int x)//起累加父亲节点答案作用
    {
    	for (int i=fr[x];i;i=net[i])
    	{
    		s[to[i]]+=s[x];
    		dfs2(to[i]);
    	}
    }
    int main()
    {
    //	freopen("brackets.in","r",stdin);
    //	freopen("brackets.out","w",stdout);
    	cin>>n;
    	cin>>st;
    	for (int i=1;i<=n;i++)
    	{
    		ch[i]=st[i-1];
    	}
    	bool lian=true;
    	for (int i=2;i<=n;i++)
    	{
    		cin>>fa[i];
    		if (fa[i]!=i-1) lian=false;
    		addedge(fa[i],i);
    	}	//建树
    	{
    		dfs1(1);
    		dfs2(1);
    	}//到这里原始答案已全部求出
    	long long ans=s[1];
    	for (int i=2;i<=n;i++)
    	{
    		ans^=s[i]*i;
    	}
    	cout<<ans<<endl;
    	return 0;
    }
    

    附:链的部分分代码(其实与正解中统计答案相似)

    	if (lian)
    	{
    		for (int i=1;i<=n;i++)
    		{
    			if (ch[i]=='(') 
    			{
    				zhan[++t]=i;
    			}
    			else 
    			{
    				if (!t) continue; 
    				s[i]=1+s[fa[zhan[t]]];
    				t--;
    			}
    		}
    		for (int i=1;i<=n;i++)
    		{
    			s[i]+=s[i-1];
    		}
    	}
    
  • 相关阅读:
    Android Studio快速导入项目
    梦断代码阅读笔记01
    Python词云生成
    Python 数据处理
    Android studio 自定义Dialog
    Android studio Activity的跳转和数据传递
    Android studio Handler消息处理2
    2.9 react组件中使用key作为prop属性命名报错
    2.3 上下margin值合并
    2.2 快速认识虚拟dom
  • 原文地址:https://www.cnblogs.com/fmj123/p/12210703.html
Copyright © 2011-2022 走看看