题目地址:
https://www.luogu.com.cn/problem/P5658
题目分析:
对于合法子串,还是要寻求子串中的关系,由于我们是逐步拼接子串的。所以我们将子串看作s1+s2的形式。s1为当前组成的字符串,s2为下一步要添加的字符串。
1.如果s2为(, 则s1+s2的子串总数即为s2的字串总数
2.如果s2为),且跟s1匹配上,分为以下几种情况
s1为()(,则s1+s2的子串总数=s1的字串总数+2
s1为((),则s1+s2的子串总数=s1的字串总数+1
s1为(),则s1+s2的子串总数=s1的字串总数
简单总结:s1+s2的子串总数=s1子串数量+该符号拼接上之后的贡献值
贡献值算法:当前贡献值=匹配的( 的贡献值+1
代码:
tree:以树结构存储输入的符号,gx表示当前位置的贡献值,num表示到当前位置的子串数量
#include<bits/stdc++.h>
using namespace std;
struct Tree
{
int i;
vector <int> son;
char str;
long long num=0,gx=0;
int fa=0;
}tree[500001];
int pp(char a,char b)
{
return a=='('&&b==')';
}
void js(int i, vector<pair<char,int>> z)
{
Tree t=tree[i];
//当前节点处理
if(t.str==')'&&!z.empty())
{
int s=z.size();
if(pp(z[s-1].first,t.str))
{
tree[i].gx=tree[tree[z[s-1].second].fa].gx+1;
}
z.pop_back();
}
else
{
z.push_back(make_pair(t.str,t.i));
}
tree[i].num=tree[i].gx+tree[tree[i].fa].num;
if(!t.son.empty())
{
for(int j=0;j<t.son.size();j++)
{
js(t.son[j],z);
}
}
}
int main()
{
int n;
cin>>n;
getchar();
char c;
for(int i=1;i<=n;i++)
{
c=getchar();
tree[i].i=i;
tree[i].str=c;
}
//首节点单独处理
for(int i=2;i<=n;i++)
{
int t;
cin>>t;
tree[t].son.push_back(i);
tree[i].fa=t;
}
//z 用于存储栈序号 第一个值为当前节点的字符,第二个值为当前字符的节点编号
vector<pair<char,int>> z;
js(1,z);
long long t=0;
for(int i=2;i<=n;i++)
{
t=t^(i*tree[i].num);
}
cout<<t;
return 0;
}