T1 标题统计
题目描述
凯凯刚写了一篇美妙的作文,请问这篇作文的标题中有多少个字符?
注意:标题中可能包含大、小写英文字母、数字字符、空格和换行符。统计标题字符数时,空格和换行符不计算在内。
输入格式
输入文件只有一行,一个字符串 s s s。
输出格式
输出文件只有一行,包含一个整数,即作文标题的字符数(不含空格和换行符)。
数据范围
规定 ∣ s ∣ |s| ∣s∣ 表示字符串 s s s 的长度(即字符串中的字符和空格数)。
对于 40 % 40\% 40% 的数据, 1 ≤ ∣ s ∣ ≤ 5 1 \le |s| \le 5 1≤∣s∣≤5,保证输入为数字字符及行末换行符。
对于 80 % 80\% 80% 的数据, 1 ≤ ∣ s ∣ ≤ 5 1 \le |s| \le 5 1≤∣s∣≤5,输入只可能包含大、小写英文字母、数字字符及行末换行符。
对于 100 % 100\% 100% 的数据, 1 ≤ ∣ s ∣ ≤ 5 1 \le |s| \le 5 1≤∣s∣≤5,输入可能包含大、小写英文字母、数字字符、空格和行末换行符。
样例说明
样例1:
标题中共有 3 3 3 个字符,这 3 3 3 个字符都是数字字符。
样例2:
标题中共有 5 5 5 个字符,包括 1 1 1 个大写英文字母, 1 1 1 个小写英文字母和 2 2 2 个数字字符,还有 1 1 1 个空格。由于空格不计入结果中,故标题的有效字符数为 4 4 4 个。
T1分析
送分题…
#include <iostream>
using namespace std;
int main()
{
string s;
int ans=0;
while (cin >> s)
ans+=s.length();
cout << ans << endl;
return 0;
}
T2 龙虎斗
题目描述
轩轩和凯凯正在玩一款叫《龙虎斗》的游戏,游戏的棋盘是一条线段,线段上有
n
n
n 个兵营(自左至右编号
1
1
1 ~
n
n
n),相邻编号的兵营之间相隔
1
1
1 厘米,即棋盘为长度为
n
−
1
n - 1
n−1 厘米的线段。
i
i
i 号兵营里有
c
i
c_i
ci 位工兵。
下面图 1 1 1 为 n = 6 n = 6 n=6 的示例:
图 1 1 1. n = 6 n = 6 n=6 的示例
轩轩在左侧,代表 “龙”;凯凯在右侧,代表 “虎”。他们以 m m m 号兵营作为分界,靠左的工兵属于龙势力,靠右的工兵属于虎势力,而 第 m m m 号兵营中的工兵很纠结,他们不属于任何一方。
一个兵营的气势为:该兵营中的工兵数 × \times × 该兵营到 m m m 号兵营的距离;参与游戏一方的势力定义为:属于这一方所有兵营的气势之和。
下面图 2 2 2 为 n = 6 , m = 4 n = 6, m = 4 n=6,m=4 的示例,其中红色为龙方,黄色为虎方:
图 2 2 2. n = 6 , m = 4 n = 6, m = 4 n=6,m=4 的示例
游戏过程中,某一刻天降神兵,共有 s 1 s_1 s1 位工兵突然出现在了 p 1 p_1 p1 号兵营。作为轩轩和凯凯的朋友,你知道如果龙虎双方气势差距太悬殊,轩轩和凯凯就不愿意继续玩下去了。为了让游戏继续,你需要选择一个兵营 p 2 p_2 p2,并将你手里的 s 2 s_2 s2 位工兵 全部 派往兵营 p 2 p_2 p2,使得双方气势差距尽可能小。
注意:你手中的工兵落在哪个兵营,就和该兵营中其他工兵有相同的势力归属(如果落在 m m m 号兵营,则不属于任何势力)。
输入格式
输入文件的第一行包含一个正整数 n n n,代表兵营的数量。
接下来的一行包含 n n n 个正整数,相邻两数之间以一个空格分隔,第 i i i 个正整数代表编号为 i i i 的兵营中起始时的工兵数量 c i c_i ci。
接下来的一行包含四个正整数,相邻两数间以一个空格分隔,分别代表 m , p 1 , s 1 , s 2 m,p_1,s_1,s_2 m,p1,s1,s2。
输出格式
输出文件有一行,包含一个正整数,即 p 2 p_2 p2,表示你选择的兵营编号。
如果存在多个编号同时满足最优,取最小的编号。
数据范围
1 < m < n , 1 ≤ p 1 ≤ n 1 < m < n, 1 \le p_1 \le n 1<m<n,1≤p1≤n。
对于 20 % 20\% 20% 的数据, n = 3 , m = 2 , c i = 1 , s 1 , s 2 ≤ 100 n = 3, m = 2, c_i = 1, s_1, s_2 \le 100 n=3,m=2,ci=1,s1,s2≤100。
另有 20 % 20\% 20% 的数据, n ≤ 10 , p 1 = m , c i = 1 , s 1 , s 2 ≤ 100 n \le 10, p_1 = m, c_i = 1, s_1, s_2 \le 100 n≤10,p1=m,ci=1,s1,s2≤100。
对于 60 % 60\% 60% 的数据, n ≤ 100 , c i = 1 , s 1 , s 2 ≤ 100 n \le 100, c_i = 1, s_1, s_2 \le 100 n≤100,ci=1,s1,s2≤100。
对于 80 % 80\% 80% 的数据, n ≤ 100 , c i , s 1 , s 2 ≤ 100 n \le 100, c_i,s_1,s_2 \le 100 n≤100,ci,s1,s2≤100。
对于 100 % 100\% 100% 的数据, n ≤ 1 0 5 , c i , s 1 , s 2 ≤ 1 0 9 n \le 10^5, c_i, s_1, s_2 \le 10^9 n≤105,ci,s1,s2≤109。
样例说明
样例 1
双方以 m = 4 m=4 m=4 号兵营分界,有 s 1 = 5 s_1 =5 s1=5 位工兵突然出现在 p 1 = 6 p_1 =6 p1=6 号兵营。
龙方的气势为: 2 × ( 4 − 1 ) + 3 × ( 4 − 2 ) + 2 × ( 4 − 3 ) = 14 \displaystyle 2 \times (4 - 1) + 3 \times (4 - 2) + 2 \times (4 - 3) = 14 2×(4−1)+3×(4−2)+2×(4−3)=14
虎方的气势为: 2 × ( 5 − 4 ) + ( 3 + 5 ) × ( 6 − 4 ) = 18 \displaystyle 2 \times (5 - 4) + (3 + 5) \times (6 - 4) = 18 2×(5−4)+(3+5)×(6−4)=18
当你将手中的 s 2 = 2 s_2 = 2 s2=2 位工兵派往 p 2 = 2 p_2 = 2 p2=2 号兵营时,龙方的气势变为:
14 + 2 × ( 4 − 2 ) = 18 \displaystyle 14 + 2 \times (4 - 2) = 18 14+2×(4−2)=18
此时双方气势相等。
样例 2
双方以 m = 5 m = 5 m=5 号兵营分界,有 s 1 = 1 s_1 =1 s1=1 位工兵突然出现在 p 1 = 4 p_1 =4 p1=4 号兵营。
龙方的气势为: 1 × ( 5 − 1 ) + 1 × ( 5 − 2 ) + 1 × ( 5 − 3 ) + ( 1 + 1 ) × ( 5 − 4 ) = 11 \displaystyle 1 \times (5 - 1) + 1 \times (5 - 2) + 1 \times (5 - 3) + (1 + 1) \times (5 - 4) = 11 1×(5−1)+1×(5−2)+1×(5−3)+(1+1)×(5−4)=11虎方的气势为: 16 × ( 6 − 5 ) = 16 \displaystyle 16 \times (6 - 5) = 16 16×(6−5)=16当你将手中的 s 2 = 1 s_2 = 1 s2=1 位工兵派往 p 2 = 1 p_2 = 1 p2=1 号兵营时,龙方的气势变为: 11 + 1 × ( 5 − 1 ) = 15 \displaystyle 11 + 1 \times (5 - 1) = 15 11+1×(5−1)=15此时可以使双方气势的差距最小。
样例 3
网盘链接:https://pan.baidu.com/s/1kzJKaoFSBoUggGm6-_GAJA 密码:md6k
T2分析
先算出左边和右边的和,然后暴力模拟当前
s
2
s_2
s2 放在
[
1
,
n
]
[1,n]
[1,n] 中任意一个位置的情况,求出一个最小差值
a
b
s
(
l
e
f
t
−
r
i
g
h
t
)
abs(left-right)
abs(left−right)即可
注意细节,
n
≤
1
0
5
n≤10^5
n≤105,
c
i
,
s
1
,
s
2
≤
1
0
9
c_i,s_1,s_2≤10^9
ci,s1,s2≤109,求和的结果会达到
1
0
14
10^{14}
1014,所以要long long,以及
p
1
p_1
p1可能在左边也可能在右边,也可能在
m
m
m 上,还有就是手里这
s
2
s_2
s2 个人同样是可以放在
m
m
m 中的
#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <vector>
using namespace std;
long long a[100100];
int main()
{
int n;scanf("%d",&n);
for (int i = 1 ; i <= n ; ++i)
scanf("%lld",&a[i]);
long long m,p1,s1,s2;
scanf("%lld%lld%lld%lld",&m,&p1,&s1,&s2);
long long left = 0,right = 0;
for (int i = 1 ; i < m ; ++i){
left += a[i] * (m - i);
}
for (int i = m + 1 ; i <= n ; ++i){
right += a[i] * (i - m);
}
if (p1 < m) left += (m - p1) * s1;
if (p1 > m) right += (p1 - m) * s1;
long long sum = abs(right - left),ans = m;
for (int i = 1 ; i <= n ; ++i){
long long vl = left;
long long vr = right;
if (i < m) vl += (m - i) * s2;
if (i > m) vr += (i - m) * s2;
long long vsum = abs(vl - vr);
if (vsum < sum){
ans = i;
sum = vsum;
}
}
printf("%lld\n",ans);
return 0;
}
T3 摆渡车
题目描述
有
n
n
n 名同学要乘坐摆渡车从人大附中前往人民大学,第
i
i
i 位同学在第
t
i
t_i
ti 分钟去等车。只有一辆摆渡车在工作,但摆渡车容量可以视为无限大。摆渡车从人大附中出发、把车上的同学送到人民大学、再回到人大附中(去接其他同学),这样往返一趟总共花费
m
m
m 分钟(同学上下车时间忽略不计)。摆渡车要将所有同学都送到人民大学。
凯凯很好奇,如果他能任意安排摆渡车出发的时间,那么这些同学的等车时间之和最小为多少呢?
注意:摆渡车回到人大附中后可以即刻出发。
输入格式
第一行包含两个正整数 n , m n,m n,m,以一个空格分开,分别代表等车人数和摆渡车往返一趟的时间。
第二行包含 n n n 个正整数,相邻两数之间以一个空格分隔,第 i i i 个非负整数 t i t_i ti 代表第 i i i 个同学到达车站的时刻。
输出格式
输出一行,一个整数,表示所有同学等车时间之和的最小值(单位:分钟)。
数据范围
对于 10 % 10\% 10% 的数据, n ≤ 10 , m = 1 , 0 ≤ t i ≤ 100 n \le 10, m=1, 0\le t_i \le 100 n≤10,m=1,0≤ti≤100。
对于 30 % 30\% 30% 的数据, n ≤ 20 , m ≤ 2 , 0 ≤ t i ≤ 100 n \le 20, m \le 2, 0 \le t_i \le 100 n≤20,m≤2,0≤ti≤100。
对于 50 % 50\% 50% 的数据, n ≤ 500 , m ≤ 100 , 0 ≤ t i ≤ 1 0 4 n \le 500, m \le 100, 0 \le t_i \le 10^4 n≤500,m≤100,0≤ti≤104。
另有 20 % 20\% 20% 的数据, n ≤ 500 , m ≤ 10 , 0 ≤ t i ≤ 4 × 1 0 6 n \le 500, m \le 10, 0 \le t_i \le 4 \times 10^6 n≤500,m≤10,0≤ti≤4×106。
对于 100 % 100\% 100% 的数据, n ≤ 500 , m ≤ 100 , 0 ≤ t i ≤ 4 × 1 0 6 n \le 500, m \le 100, 0 \le t_i \le 4 \times 10^6 n≤500,m≤100,0≤ti≤4×106。
样例说明
样例 1
同学 1 1 1 和同学 4 4 4 在第 3 3 3 分钟开始等车,等待 0 0 0 分钟,在第 3 3 3 分钟乘坐摆渡车 出发。摆渡车在第 4 4 4 分钟回到人大附中。
同学 2 2 2 和同学 3 3 3 在第 4 4 4 分钟开始等车,等待 0 0 0 分钟,在第 4 4 4 分钟乘坐摆渡车 出发。摆渡车在第 5 5 5 分钟回到人大附中。
同学 5 5 5 在第 5 5 5 分钟开始等车,等待 0 0 0 分钟,在第 5 5 5 分钟乘坐摆渡车出发。自此所有同学都被送到人民大学。总等待时间为 0 0 0。
样例 2
同学 3 3 3 在第 1 1 1 分钟开始等车,等待 0 0 0 分钟,在第 1 1 1 分钟乘坐摆渡车出发。摆渡车在第 6 分钟回到人大附中。
同学 4 4 4 和同学 5 5 5 在第 5 5 5 分钟开始等车,等待 1 1 1 分钟,在第 6 6 6 分钟乘坐摆渡车出发。摆渡车在第 11 11 11 分钟回到人大附中。
同学 1 1 1 在第 11 11 11 分钟开始等车,等待 2 2 2 分钟;同学 2 2 2 在第 13 13 13 分钟开始等车,等待 0 0 0 分钟。他/她们在第 13 13 13 分钟乘坐摆渡车出发。自此所有同学都被送到人民大学。总等待时间为 4 4 4。可以证明,没有总等待时间小于 4 4 4 的方案。
T3分析
dp或者记忆化搜索。
相对来说dp对算法要求高一些,需要考虑状态转移的优化或者剪枝
解法 I
记忆化搜索相对来说简单一些,比赛的时候,既然可以想的到记忆化搜索,何必再去推个dp公式呢…当然10分钟解决dp所有问题的dalao就不用考虑这种东西了…
首先考虑一下这个问题中存在的状态,显然是
[
人
]
[
时
间
]
[人][时间]
[人][时间]两者的结合,那么考虑
f
[
i
]
[
j
]
f[i][j]
f[i][j],第
i
i
i 个人,考虑时间
j
j
j ,能达到的最佳方案,但是显然
j
j
j 会达到
4
×
1
0
6
4 \times 10^6
4×106,但是这里我们可以发现一件事,一个人是不可能等待超过
m
m
m 分钟,所以其实状态可以表示成
f
[
i
]
[
j
]
表
示
到
第
i
个
人
,
他
的
等
待
时
间
是
j
的
时
候
能
达
到
的
最
佳
方
案
f[i][j]表示到第 i 个人,他的等待时间是 j 的时候能达到的最佳方案
f[i][j]表示到第i个人,他的等待时间是j的时候能达到的最佳方案
那么思考一下状态转移…显然最容易想到的状态就是对当前状态
f
[
i
]
[
j
]
f[i][j]
f[i][j] 考虑这辆车直接发车,或者等第
i
+
1
i + 1
i+1个同学来,或者继续等到
i
+
2
i + 2
i+2 个同学来。
然后考虑一下复杂度,显然
O
(
n
2
∗
m
)
O(n^2*m)
O(n2∗m)足矣…那就,做完了呀
#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
int n,m;
int a[10000];
int f[550][550]; //第i个人等待时间为j的最佳结果
int solve(int now,int Time){
//n个人都结束了则返回0
if (now >= n ) return 0;
//若当前时间<当前同学的来的时间,则将时间拉到当前同学来的时间
if (a[now] > Time) return solve(now,a[now]);
//当前状态出现过
if (f[now][Time - a[now]]) return f[now][Time - a[now]];
int sum = 0,ans = 0;
int i = now;
for (; i < n ;++i){
if (a[i] > Time) break;
sum += a[i];
ans += Time - a[i];
}
ans += solve(i , Time + m);
for (; i < n ; ++i){
sum += a[i];
ans = min(ans, solve(i + 1,a[i] + m) + a[i] * (i - now + 1) - sum);
}
return f[now][Time - a[now]] = ans;
}
int main(){
scanf("%d%d",&n,&m);
for (int i = 0 ; i < n ; ++i) scanf("%d",&a[i]);
sort(a,a+n);
printf("%d\n",solve(0,0));
return 0;
}
解法 II
引理:对于每个乘客,如果他开始等待的时刻为 t t t,那么搭载他的车的发车时间 t 0 ∈ [ t , t + m ) t_0 \in [t, t + m) t0∈[t,t+m)。
证明:如果存在一种发车时间 ≥ t + m \ge t + m ≥t+m,那么发车时间一定可以提早若干个 m m m 使得 t 0 t_0 t0 到达 [ t , t + m ) [t, t + m) [t,t+m)。这样不会影响其他 ≥ t + m \ge t + m ≥t+m 的发车时间,不会干扰后面的人等车。
我们考虑 DP 状态涉及: f [ i , j ] f[i, j] f[i,j] 表示搭载了前 i i i 个人,搭载第 i i i 个人的摆渡车的发车时间为 t i + j t_i + j ti+j 的最小等候时间总和。朴素的转移方程为:
f [ i , j ] = min 0 ≤ k < i , 0 ≤ p < m { f [ k , p ] + c o s t ( k + 1 , i , t i + j ) } \displaystyle f[i,j] = \min_{0 \le k < i, 0 \le p < m}\{f[k, p] + cost(k + 1, i, t_i + j)\} f[i,j]=0≤k<i,0≤p<mmin{f[k,p]+cost(k+1,i,ti+j)}
其中 c o s t ( i , j , k ) cost(i, j, k) cost(i,j,k) 表示第 i i i ~ j j j 个人在 k k k 时间乘车的等候时间总和。注意转移过程中有 t i + j ≥ t k + p + m t_i + j \ge t_k + p + m ti+j≥tk+p+m(当前这趟车比上一趟车至少晚 m m m)的限制!
这个式子直接计算是 O ( n 3 m 2 ) \mathcal{O}(n^3m^2) O(n3m2) 的,接下来考虑转移如何优化。上述式子中,我们通过对 t i t_i ti 做前缀和可以 O ( 1 ) \mathcal{O}(1) O(1) 计算出 c o s t cost cost 的值。我们再记 g [ i , j ] = min 0 ≤ j < m f [ i , j ] g[i, j] = \min_{0 \le j < m}f[i, j] g[i,j]=min0≤j<mf[i,j](这个前缀 min \min min 可以在转移过程中维护),转移方程化为 f [ i , j ] = min 0 ≤ k < i { g [ k , x ] + c o s t } f[i, j] = \min_{0 \le k < i}\{g[k, x] + cost\} f[i,j]=min0≤k<i{g[k,x]+cost},其中 x = min ( m − 1 , t i + j − t k − m ) x = \min(m - 1, t_i + j - t_k - m) x=min(m−1,ti+j−tk−m) 且 x ≥ 0 x \ge 0 x≥0,时间复杂度优化为 O ( n 2 m ) \mathcal{O}(n^2m) O(n2m)。
#include <cstdio>
#include <algorithm>
int t[505], p[1005 * 105];
long long f[1005 * 105], g[505][105];
int main() {
int n, m, P = 0; scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++i) {
scanf("%d", t + i);
for(int k = 0; k <= m; ++k) p[++P] = t[i] + k;
}
std::sort(t + 1, t + n + 1);
std::sort(p + 1, p + P + 1); P = std::unique(p + 1, p + P + 1) - p - 1;
t[0] = -4e6;
int ans = 2017011328;
for(int i = 1, k = 0, pi; i <= P; ++i) {
f[i] = ans; pi = p[i];
while(k < n && t[k + 1] <= pi) {
++k;
for(int i = 0; i <= m; ++i) g[k][i] = 2017011328;
}
for(int j = k, c = 0; j >= 1; --j) {
c += pi - t[j];
if(t[j - 1] != t[j] && pi - t[j - 1] >= m) f[i] = std::min(f[i], c + g[j - 1][std::min(m, pi - m - t[j - 1])]);
}
if(g[k][std::min(m, pi - t[k])] > f[i]) g[k][std::min(m, pi - t[k])] = f[i];
for(int j = 1; j <= m; ++j) g[k][j] = std::min(g[k][j], g[k][j - 1]);
}
printf("%lld\n", g[n][m]);
}
T4 对称二叉树
题目描述
一棵有点权的有根树如果满足以下条件,则被轩轩称为 对称二叉树:
-
- 二叉树;
-
- 将这棵树 所有 节点的左右子树交换,新树和原树对应位置的结构相同且点权相等。
下图中节点内的数字为权值,节点外的 i d id id 表示节点编号。
现在给出一棵二叉树,希望你找出它的一棵子树,该子树为对称二叉树,且节点数最多。请输出这棵子树的节点数。
注意:只有树根的树也是对称二叉树。本题中约定,以节点 T T T 为子树根的一棵 “子树” 指的是:节点 T T T 和它的 全部 后代节点构成的二叉树。
输入格式
第一行一个正整数 n n n,表示给定的树的节点的数目,规定节点编号 1 1 1~ n n n,其中节点 1 1 1 是树根。
第二行 n n n 个正整数,用一个空格分隔,第 i i i 个正整数 v i v_i vi 代表节点 i i i 的权值。
接下来 n n n 行,每行两个正整数 l i , r i l_i, r_i li,ri,分别表示节点 i i i 的左右孩子的编号。如果不存在左 / 右孩子,则以 − 1 -1 −1 表示。两个数之间用一个空格隔开。
输出格式
输出文件共一行,包含一个整数,表示给定的树的最大对称二叉子树的节点数。
数据范围
共 25 25 25 个测试点。
v i ≤ 1000 v_i \le 1000 vi≤1000。
测试点 1 1 1 ~ 3 3 3, n ≤ 10 n \le 10 n≤10,保证根结点的左子树的所有节点都没有右孩子,根结点的右子树的所有节点都没有左孩子。
测试点 4 4 4 ~ 8 8 8, n ≤ 10 n \le 10 n≤10。
测试点 9 9 9 ~ 12 12 12, n ≤ 1 0 5 n \le 10^5 n≤105,保证输入是一棵 “满二叉树”。
测试点 13 13 13 ~ 16 16 16, n ≤ 1 0 5 n \le 10^5 n≤105,保证输入是一棵 “完全二叉树”。
测试点 17 17 17 ~ 20 20 20, n ≤ 1 0 5 n \le 10^5 n≤105,保证输入的树的点权均为 1 1 1。
测试点 21 21 21 ~ 25 25 25, n ≤ 1 0 6 n \le 10^6 n≤106。
本题约定:
层次:节点的层次从根开始定义起,根为第一层,根的孩子为第二层。树中任一节点的层次等于其父亲节点的层次加 1 1 1。
树的深度:树中节点的最大层次称为树的深度。
满二叉树:设二叉树的深度为 h h h,且二叉树有 2 h − 1 2^h - 1 2h−1 个节点,这就是满二叉树。
完全二叉树:设二叉树的深度为 h h h,除第 h h h 层外,其它各层的结点数都达到最大个数,第 h h h 层所有的结点都连续集中在最左边,这就是完全二叉树。
样例说明
样例 1
最大的对称二叉子树为以节点 2 2 2 为树根的子树,节点数为 1 1 1。
样例 2
最大的对称二叉子树为以节点 7 7 7 为树根的子树,节点数为 3 3 3。
T4分析
第三题做太久了就没想到吧这第四题跟第三题比起来跟送的一样…
没啥东西…顶多也就是个PAT难度的题目…
首先考虑一点,直接check的复杂度是多少,乍一看以为是
O
(
n
2
)
O(n^2)
O(n2) 的就基本上崩了。。
实际上考虑最慢的情况就是一颗完全对称的树,那么遍历一次的复杂度是多少呢?
O
(
n
)
O(n)
O(n)因为每个点都要被访问到,然而并不是这样…显然每次左右分别往下遍历的话,遍历一次的复杂度也就只有
O
(
l
o
g
n
)
O(logn)
O(logn)罢了…所以…就做完了呀…
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)就过了…甚至还可以做一下优化,比如先预处理出当前节点下子树的大小,那么每次在check之前可以判断…加个最优化剪枝虽然应该没什么大用
#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
int n;
int a[1001000],lson[1001000],rson[1001000];
int check(int l,int r){
if (l == -1 && r == -1) return 1;
if (l == -1 || r == -1) return -1;
if (a[l] != a[r]) return -1;
int lval = check(lson[l],rson[r]);
int rval = check(rson[l],lson[r]);
if (lval == -1 || rval == -1) return -1;
return lval + rval + 1;
}
int main() {
scanf("%d",&n);
for (int i = 1 ; i <= n ; ++i) scanf("%d",&a[i]);
for (int i = 1 ; i <= n ; ++i){
scanf("%d%d",&lson[i],&rson[i]);
}
int ans = 1;
for (int i = 1 ; i <= n ; ++i){
int temp = check(lson[i],rson[i]);
if (temp != -1) ans = max(ans,temp);
}
printf("%d\n",ans);
return 0;
}