zoukankan      html  css  js  c++  java
  • [被踩计划] 题解 括号树

    为什么叫被踩记录呢?因为感觉自己之前真的是太菜了,打算把之前联赛等考过的题目做一做,看看自已以前有多菜,所以取名叫被踩记录。

    题目链接

    题目分析

    先考虑在一个序列上面做,然后再扩展到树上。

    首先,我们先计算以每个位置作为结尾的合法字串个数,然后再通过后缀和统计答案。

    如何求以某个位置作为结尾的合法字串个数?我们可以对每个位置找到长度最短的一个合法后缀,然后就转化成了一个子问题,可以用dp做了。

    举个例子:对于括号序列)())()(()),以最后一个位置作为结尾的合法后缀就是括号序列)())()以最后一个位置作为结尾的合法后缀数量加一,因为)())()(())=)())()+(()),而(())是一个合法括号串。

    如何求出这个长度最短的一个合法后缀?可以用栈来解决这个问题,栈中维护的大概是这样一个序列))...))((...((,同时维护栈中每个括号对应的位置,再分类讨论一下就行了,每次操作都是 (mathcal O(1)) 的。

    扩展到树上,做法还是一样的,可以再dfs的同时顺便维护栈,只要回退的时候恢复就行了。

    当然也可以不用dfs,考虑到每次弹栈然后入栈类似一个树的结构,所以只需要维护在这个“栈树”上的父亲即可实现弹栈和入栈了。

    参考代码

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int maxn=500005;
    char s[maxn];
    int pa[maxn],top[maxn],fa[maxn];
    long long cnt[maxn];
    int main(){
    	int n;
    	scanf("%d%s",&n,s+1);
    	pa[1]=0,top[1]=1;
    	for(int i=2;i<=n;++i){
    		int f;scanf("%d",&f);fa[i]=f;
    		if(s[i]=='('||!top[f]||s[top[f]]==')')
    			pa[top[i]=i]=top[f];
    		else
    			top[i]=pa[top[f]],cnt[i]=cnt[fa[top[f]]]+1;
    	}
    	for(int i=2;i<=n;++i)cnt[i]+=cnt[fa[i]];
    	long long ans=0;
    	for(int i=1;i<=n;++i)ans^=cnt[i]*i;
    	printf("%lld
    ",ans);
    	return 0;
    }
    
    
  • 相关阅读:
    伐木工和森林的故事(一)
    EclipsePDT PHP的开发环境配置
    奇怪的using
    [团队开发]SERVER2008下无法安装VS2008 SP1 和 TFS2008 SP1补丁
    写在七夕
    一点点的松懈,就可以毁掉自己!
    2008,到今天我不后悔
    细节决定成败,注意的事情需要做到,而不是听完了当耳边风
    正视差距,展望2008!
    ZendStudio5.5调式环境配置
  • 原文地址:https://www.cnblogs.com/lsq147/p/13746329.html
Copyright © 2011-2022 走看看