【NOIP/CSP2019】D1T2 括号树

原题:ios

 

 

由于是NOIP题,因此首先先看特殊数据,前35分是一条长度不超过2000的链,N^2枚举全部子区间暴力check就能拿到分ide

其次能够思考特殊状况,一条链的状况怎么作spa

OI系列赛事的特殊性质分不少时候不只是帮助得分,还帮助选手找到思路code

观察合法串的形状,能够发现主要由括号嵌套和并列组成blog

嵌套好说,一对匹配的括号对答案贡献为1(里边包的东西不合法的括号不算匹配的括号)ci

对于并列的括号,能够发现若是要把两对匹配的括号并列算做一个贡献,那么必需要求这两个括号挨着,即右边的左括号的左边是左边的右括号get

思考涉及到子区间的问题时,一个常见的思路是肯定一个端点,考虑另外一个string

由于括号匹配是从左到右添加进栈的,那么不妨肯定右端点,对于加入的右括号咱们只需考虑其能匹配多少个左端点it

能够发现,某个右括号和跟他匹配的左括号算1个贡献io

若是左括号的左边是匹配上的右括号,那么这个右括号做为右端点的合法区间均可以直接接上右边匹配的一对括号算做贡献1

那么思路就很清楚了,总结一下,只考虑对于匹配上的右括号,有多少个左端点使得区间合法

它本身的左括号算贡献1,而后再把右端点为左括号下标-1的合法区间数接上

用g[i]表示点i为右端点的方案数,f[i]表示g[i]的前缀和(用于统计答案)

那么若是某个点是左括号或匹配不上的右括号,g[i]为0

若是是匹配上左括号j的右括号,g[i]=g[j-1]+1

那么对于一棵树的状况,其实能够发现,只须要dfs树,而后回溯的时候把新加进来的括号退栈就跟序列的状况没什么区别

(固然别忘了刚才退栈的括号回溯时要补进)

 

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 using namespace std;
 7 #define LL long long
 8 int rd(){int z=0,mk=1;  char ch=getchar();
 9     while(ch<'0'||ch>'9'){if(ch=='-')mk=-1;  ch=getchar();}
10     while(ch>='0'&&ch<='9'){z=(z<<3)+(z<<1)+ch-'0';  ch=getchar();}
11     return z*mk;
12 }
13 struct edg{int nxt,y;}e[510000];  int lk[510000],ltp=0;
14 void ist(int x,int y){  e[++ltp]=(edg){lk[x],y};  lk[x]=ltp;}
15 int n,fth[510000];  char s[510000];
16 LL f[510000],g[510000];
17 int q[510000],hd=0;
18 void dfs(int x){
19     //cout<<"x: "<<x<<" f: "<<f[x]<<" g: "<<g[x]<<endl;
20     //for(int i=1;i<=hd;++i)  cout<<q[i]<<" ";
21     //cout<<endl;
22     for(int i=lk[x];i;i=e[i].nxt){
23         int tmp=q[hd];
24         if(s[e[i].y]==')' && hd){
25             g[e[i].y]=g[fth[tmp]]+1;
26             f[e[i].y]=f[x]+g[e[i].y];
27             --hd;
28         }
29         else{
30             if(s[e[i].y]=='(')  q[++hd]=e[i].y;
31             //由于栈里只会有左括号,因此存下标表示这里有个左括号就vans了
32             g[e[i].y]=0;
33             f[e[i].y]=f[x];
34         }
35         dfs(e[i].y);
36         if(s[e[i].y]==')' && tmp)  q[++hd]=tmp;
37         //注意不是hd!=0
38         else if(s[e[i].y]=='(')  --hd;
39     }
40 }
41 int main(){
42     freopen("ddd.in","r",stdin);
43     cin>>n;
44     scanf("%s",s+1);
45     for(int i=2;i<=n;++i)  fth[i]=rd(),ist(fth[i],i);
46     //q[++hd]=1;  f[1]=0,g[1]=0;  注意s[1]不必定是'('
47     if(s[1]=='(')  q[++hd]=1;  f[1]=0,g[1]=0;
48     dfs(1);
49     LL ans=0;
50     for(int i=1;i<=n;++i)  ans^=i*f[i];
51     cout<<ans<<endl;
52     return 0;
53 }
View Code
相关文章
相关标签/搜索