Accepts: 926
Submissions: 2432
Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 65536/65536 K (Java/Others)
Problem Description
度度熊、光羽、带劲三个人是好朋友。
度度熊有一棵nnn个点的有根树,其中1号点为树根。除根节点之外,每个点都有父节点,记iii号点的父节点为fa[i]fa[i]fa[i]。
度度熊称点iii和点jjj是兄弟(其中i≠ji \neq ji≠j)当且仅当fa[i]=fa[j]fa[i]=fa[j]fa[i]=fa[j]。
第iii个点的权值为AiA_iAi。现要求选出一个点集,该点集合法当且仅当点集中至多只有一对兄弟。
度度熊想知道,在所有可行的点集中,权值和最大以及最小的点集权值和分别是多少?
Input
第一行一个数,表示数据组数TTT。
每组数据第一行一个整数nnn;第二行n−1n-1n−1个数,表示fa[2],fa[3],..,fa[n]fa[2],fa[3],..,fa[n]fa[2],fa[3],..,fa[n];第三行nnn个数,表示AiA_iAi。
数据组数T=100,满足:
其中90%的数据满足n≤1000n \le 1000n≤1000。
Output
每组数据输出一行,每行包含两个数,分别表示权值和的最大值和最小值。
Sample Input
Copy
2
5
1 1 2 2
-4 -4 -1 -2 -5
5
1 1 3 2
-1 -4 2 0 -2
Sample Output
Copy
0 -15
2 -7
Statistic | Submit | Clarifications | Back
题解:将每个元素加入到对应父亲的set里,然后访问最大最小值即可。。。水题一道
#include
#include
#include
#include
using namespace std;
#define ll long long
#define mod 1000000007
ll n,a[100005],ans1=0,ans2=0;
int f[100005];
sets[100005];set::iterator it;
int main(void)
{
int T;
scanf("%d",&T);
while(T--)
{
ans1=0,ans2=0;
scanf("%lld",&n);
for(int i=1;i<=n;i++)
s[i].clear();
for(int i=2;i<=n;i++)
scanf("%d",&f[i]);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]),s[f[i]].insert(a[i]);
for(int i=0;i<=n;i++)
{
if(s[i].empty()==0)
{
it=s[i].end();it--;
if((*it)>0) ans2+=(*it),s[i].erase(it);
}
if(s[i].empty()==0)
{
it=s[i].begin();
if((*it)<0) ans1+=(*it),s[i].erase(it);
}
}
ll mx=0,mn=0;
for(int i=0;i<=n;i++)
{
if(s[i].empty())
continue;
it=s[i].begin();
mn=min(mn,(*it));
it=s[i].end();it--;
mx=max(mx,(*it));
}
printf("%lld %lld\n",ans2+mx,ans1+mn);
}
return 0;
}