Description
给出一个 n n 个节点个叶子节点的树,以 1 1 为根,给出每个叶子节点点权,对于非叶子节点,有个点取其儿子节点中权值最大值作为自己的权值,有 n−l−k n − l − k 个点取其儿子节点中权值最小值作为自己的权值,问 1 1 节点的权值最小值和最大值
Input
第一行输入两个整数,之后输入 n1 n 1 个整数 p2,p2,...,pn p 2 , p 2 , . . . , p n ,其中 pi p i 表示 i i 节点的父亲节点,最后输入个整数 ai a i ,如果该点是叶子节点则 ai a i 表示该叶子节点的权值,否则 ai=0 a i = 0
(2≤n≤105,0≤k≤n,0≤ai≤109,k+l≤n) ( 2 ≤ n ≤ 10 5 , 0 ≤ k ≤ n , 0 ≤ a i ≤ 10 9 , k + l ≤ n )
Output
输出 1 1 节点权值的最小值和最大值
Sample Input
6 1
1 1 2 2 3
0 0 0 1 3 2
Sample Output
2 3
Solution
只考虑求最小值,最大值类似,如果要最小值从叶子节点到达根节点,那么这个点的祖先结点必须全部取最小值,故直接从根节点开始,只要深度不超过当前可以用的最小值数就可以接着取最小值,但是注意到如果一个点只有一个儿子节点那么在这个点就不用浪费一个最小值,体现在深度上就是不增加深度往下搜
Code
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const int INF=0x3f3f3f3f,maxn=100005;
int n,mx,mn,a[maxn];
vector<int>g[maxn];
int dfs_min(int u,int deep)
{
if(g[u].size()==0)return a[u];
if(g[u].size()==1)return dfs_min(g[u][0],deep);
if(mn>=deep)
{
int ans=INF;
for(int i=0;i<g[u].size();i++)
ans=min(ans,dfs_min(g[u][i],deep+1));
return ans;
}
else
{
int ans=0;
for(int i=0;i<g[u].size();i++)
ans=max(ans,dfs_min(g[u][i],deep+1));
return ans;
}
}
int dfs_max(int u,int deep)
{
if(g[u].size()==0)return a[u];
if(g[u].size()==1)return dfs_max(g[u][0],deep);
if(mx>=deep)
{
int ans=0;
for(int i=0;i<g[u].size();i++)
ans=max(ans,dfs_max(g[u][i],deep+1));
return ans;
}
else
{
int ans=INF;
for(int i=0;i<g[u].size();i++)
ans=min(ans,dfs_max(g[u][i],deep+1));
return ans;
}
}
int main()
{
while(~scanf("%d%d",&n,&mn))
{
for(int i=1;i<=n;i++)g[i].clear();
for(int i=2;i<=n;i++)
{
int t;
scanf("%d",&t);
g[t].push_back(i);
}
int l=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
if(g[i].size()==0)l++;
}
mx=n-l-mn;
printf("%d %d\n",dfs_min(1,1),dfs_max(1,1));
}
return 0;
}