题目背景
本题中合法括号串的定义如下:
()
是合法括号串。- 如果
A
是合法括号串,则(A)
是合法括号串。 - 如果
A
,B
是合法括号串,则AB
是合法括号串。
本题中子串与不同的子串的定义如下:
- 字符串
S
的子串是S
中连续的任意个字符组成的字符串。S
的子串可用起始位置 ll 与终止位置 rr 来表示,记为 S (l, r)S(l,r)(1 leq l leq r leq |S |1≤l≤r≤∣S∣,|S |∣S∣ 表示 S 的长度)。 S
的两个子串视作不同当且仅当它们在S
中的位置不同,即 ll 不同或 rr 不同。
题目描述
一个大小为 nn 的树包含 nn 个结点和 n − 1n−1 条边,每条边连接两个结点,且任意两个结点间有且仅有一条简单路径互相可达。
小 Q 是一个充满好奇心的小朋友,有一天他在上学的路上碰见了一个大小为 nn 的树,树上结点从 11 ∼ nn 编号,11 号结点为树的根。除 11 号结点外,每个结点有一个父亲结点,uu(2 leq u leq n2≤u≤n)号结点的父亲为 f_ufu(1 ≤ f_u < u1≤fu<u)号结点。
小 Q 发现这个树的每个结点上恰有一个括号,可能是(
或)
。小 Q 定义 s_isi 为:将根结点到 ii 号结点的简单路径上的括号,按结点经过顺序依次排列组成的字符串。
显然 s_isi 是个括号串,但不一定是合法括号串,因此现在小 Q 想对所有的 ii(1leq ileq n1≤i≤n)求出,s_isi 中有多少个互不相同的子串是合法括号串。
这个问题难倒了小 Q,他只好向你求助。设 s_isi 共有 k_iki 个不同子串是合法括号串, 你只需要告诉小 Q 所有 i imes k_ii×ki 的异或和,即:
(1 imes k_1) ext{xor} (2 imes k_2) ext{xor} (3 imes k_3) ext{xor} cdots ext{xor} (n imes k_n)(1×k1) xor (2×k2) xor (3×k3) xor ⋯ xor (n×kn)
其中 xorxor 是位异或运算。
输入格式
第一行一个整数 nn,表示树的大小。
第二行一个长为 nn 的由(
与)
组成的括号串,第 ii 个括号表示 ii 号结点上的括号。
第三行包含 n − 1n−1 个整数,第 ii(1 leq i lt n1≤i<n)个整数表示 i + 1i+1 号结点的父亲编号 f_{i+1}fi+1。
输出格式
仅一行一个整数表示答案。
输入输出样例
5 (()() 1 1 2 2
6
说明/提示
【样例解释1】
树的形态如下图:
将根到 1 号结点的简单路径上的括号,按经过顺序排列所组成的字符串为 (
,子串是合法括号串的个数为 00。
将根到 2 号结点的字符串为 ((
,子串是合法括号串的个数为 00。
将根到 3 号结点的字符串为 ()
,子串是合法括号串的个数为 11。
将根到 4 号结点的字符串为 (((
,子串是合法括号串的个数为 00。
将根到 5 号结点的字符串为 (()
,子串是合法括号串的个数为 11。
【数据范围】
题解:去年0分题,哎////链分如下~
#include<cstdio> #include<iostream> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> #include<bits/stdc++.h> typedef long long ll; using namespace std; const int N=500003; char tree[N]; int f[N]; ll sum[N],lst[N]; int n,t; ll ans; int main(){ freopen("5658.in","r",stdin); freopen("5658.out","w",stdout); scanf("%d",&n); scanf("%s",tree+1); //for(int i=1;i<=n;i++) cin>>tree[i]; for(int i=2;i<=n;i++) scanf("%d",&f[i]); stack <int> s; for(int i=1;i<=n;i++){ if(tree[i]==')'){ if(s.empty()) continue; t=s.top(); lst[i]=lst[t-1]+1; s.pop(); } else s.push(i); } for(int i=1;i<=n;i++){ sum[i]=sum[i-1]+lst[i]; ans=ans^(ll)((ll)i*sum[i]); } cout<<ans<<endl; return 0; }
题解:我他妈的终于改对了。原来自己写,然后就是改不对,气死我了,几乎对着题解写了
结果我发现add写错了 我大无语
#include<cstdio> #include<iostream> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> #include<bits/stdc++.h> typedef long long ll; using namespace std; const int N=500003; char tree[N]; int fa[N],head[N],cnt; ll sum[N],lst[N]; int n,t; ll ans; struct node{ int next; int to; }e[N]; void add(int x,int y){ e[++cnt].to=y; e[cnt].next=head[x]; head[x]=cnt; } int s[N],top; void dfs(int x){ int tmp=0; if(tree[x] ==')' && top){ tmp=s[top]; lst[x] = lst[fa[tmp]] + 1; --top; } else if(tree[x] == '(') s[++ top] = x; sum[x]=sum[fa[x]]+lst[x]; for(int i=head[x];i;i=e[i].next) dfs(e[i].to); if(tmp != 0) s[++top]=tmp; else if(top) --top; } int main(){ freopen("5658.in","r",stdin); freopen("5658.out","w",stdout); scanf("%d",&n); scanf("%s",tree+1); for(int i=2;i<=n;i++){ scanf("%d",&fa[i]); add(fa[i],i); } dfs(1); for(int i=1;i<=n;i++) ans=ans^(ll)((ll)i*sum[i]); cout<<ans<<endl; return 0; }