2021.8.13提高B组模拟5T2 Crisis(小根堆)

Posted SSL_LKJ

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021.8.13提高B组模拟5T2 Crisis(小根堆)相关的知识,希望对你有一定的参考价值。

Crisis

题目大意

最近几年,一场新的金融危机爆发了,这场危机使得很多人陷入的经济问题的困境。一些X公司的员工试图通过要求加薪度过这一难关。
X公司有着严格的等级制度,除了公司所有者小H以外,其他人都有一个直属上司。没有下属的员工称为工人,其他人则称为领导者。
为了加薪,工人们都会向他们的上司提交请愿书。当然,每个领导者都希望自己的下属能够尽可能快乐的工作,所以当至少有T%的下属提交请愿书时,那么这个领导者就会向自己的上司提交请愿书。计算百分比时,领导者只会计算直属上司是他的下属,当然,他也只会提交一次请愿书。
如果最会小H收到了超过T%的请愿书,那么他将为所有工人们加薪。现在给出公司的构架和T的数值,你需要计算至少有多少工人提交请愿书才能使得小H给工人加薪。

输入样例

第一行N,T(1≤N≤100000,1≤T≤100)。N表示公司的总人数(不包括小H)。每个员工编号为1到N。小H编号为0 。
第二行有N数,第I个数表示编号的员工直属上司的编号。

1.

3 100
0 0 0

2.

3 50
0 0 0

3.

14 60
0 0 1 1 2 2 2 5 7 5 7 5 7 5

输出样例

一个数,最小需求的工人数。

1.

3

2.

2

3.

5

1≤N≤100000,1≤T≤100

解题思路

我们可以先求出:
**每个节点需要多少个子节点(直系儿子)**才能向上递交请愿书

例如第三个样例(括号为所最少需要的节点数)
0 ( 2 ) 0(2) 02
1 ( 2 ) 2    ( 2 ) 1(2)2~~(2) 122  2
3 ( 0 ) 4    ( 0 ) 5    ( 3 ) 6    ( 0 ) 7 ( 2 ) 3(0)4 ~~(0)5~~(3)6~~(0)7(2) 304  05  36  072
8 ( 0 ) 10 ( 0 ) 12 ( 0 ) 14 ( 0 ) 9 ( 0 ) 11 ( 0 ) 13 ( 0 ) 8(0)10(0)12(0)14(0)9(0)11(0)13(0) 8010012014090110130

跑一遍bfs/dfs求出它的bfs/dfs序

最底端开始遍历节点

如果当前节点有儿子,则在堆中取出前k个数累加起来,再放入父节点的小根堆

k当前节点最少所需要的节点数

否则,就直接将 1 1 1放入父节点的小根堆中(因为只有工人是没有儿子的

AC代码

#include<cstdio>
#include<queue>
using namespace std;
int n,T,t,tot,head,tail;
int f[100005],p[100005],hd[100005],fa[100005],son[100005],need[100005],needson[100005];
struct node
{
	int to,next;
}a[100005];
struct work
{
	int x;
	bool operator<(const work&a)const
	{
		return x>a.x;
	}
};
void add(int x,int y)
{
	a[++tot]=(node){y,hd[x]};
	hd[x]=tot;
}
void bfs()//求bfs序
{
	p[++tail]=0;
	f[++t]=0;
	while(head<tail)
	{
		int x=p[++head];
		for(int i=hd[x];i;i=a[i].next)
		{
			p[++tail]=a[i].to;
			f[++t]=a[i].to;
		}
	}
}
priority_queue<work>q[100005];
int main()
{
	scanf("%d%d",&n,&T);
	for(int i=1;i<=n;i++)
	{
		int x;
		scanf("%d",&x);
		add(x,i);
		son[x]++;
		fa[i]=x;//x的父亲为i
	}
	for(int i=0;i<=n;i++)//求出每个节点需要的儿子
		if(son[i]==0)need[i]=1;
		else 
		{
			if(son[i]*T%100==0)needson[i]=son[i]*T/100;
			else needson[i]=int(son[i]*T/100)+1;
		}
	bfs();
	for(int i=t;i>=1;i--)//遍历每个节点
	{
		int x=f[i];
		if(son[x]!=0)
		{
			int o=0;
			while(o<needson[x])
			{
				o++;
				work xx=q[x].top();
				need[x]+=xx.x;
				q[x].pop();
			}
		}
		q[fa[x]].push((work){need[x]});
	}
	printf("%d",need[0]);
	return 0;
}

谢谢

以上是关于2021.8.13提高B组模拟5T2 Crisis(小根堆)的主要内容,如果未能解决你的问题,请参考以下文章

2021.7.16提高B组模拟5T2 图书馆(dp)

2021.8.13提高B组模拟5T1 Brothers(暴力)

2021.8.13提高B组模拟5T3 Word (暴力)

2021.8.13提高B组模拟5T1 Brothers(暴力)

2021.8.13提高B组模拟5T3 Word (暴力)

2017.12.09NOIP提高组模拟赛A组