[GDOIpj221C] 流水线

第三题 流水线
提交文件: line.cpp
输入文件: line.in
输出文件: line.out
时间空间限制: 2 秒, 256 MB
在计算机组成原理这门课中,小明的老师布置了实现 CPU 流水线的作业。小明打算设计出一个效率最高的流水线。简单来说,流水线就是 将 CPU 分成若干个任务模块,而一个模块又可以继续划分成更小的模块,小模块可以划分成更小的小小模块……根据常识我们知道把一个任务划分后,每一个部分的代价会变少,但是可能会产生额外的代价。所以小明希望你帮助他解决这个问题。

我们可以用一棵以 1 为根的有根树来描述模块之间的关系,每个节点是一个模块,每个节点的点权对应着该模块的时间代价。每一个非叶子节点可以划分成该节点的儿子节点对应的模块。

每个模块都有一定的时间代价,而流水线最后的效率我们可以用划分的模块数乘上模块中时间代价最大的一个来表示,时间代价越小,流水线的效率越高。也就是说,假如小明最后把 CPU 划分为了 m 个模块,每个模块的代价为 \(w_1, w_2, \cdots , w_m\),则总代价为 \(m \cdot max(w_1, w_2,\cdots, w_m)\)。另外,我们认为根节点对应的模块不往下划分模块也是一种合法的方案。

请你帮小明找到效率最高的流水线设计方案吧
输入格式
第一行一个正整数 \(n\),表示模块对应有根树的节点个数。
第二行 \(n\) 个整数,表示 \(n\) 个模块的时间代价 \(w_i\)
第三行 \(n − 1\) 个数 \(f_i(2 ≤ i ≤ n)\),表示节点 \(2,\cdots , n\) 在有根树中的父节点。保证给出的是一棵以 \(1\) 为根的树。
输出格式
一个整数 T,表示最小的时间代价。
样例数据
line.in line.out
5
10 7 3 3 2
1 1 2 2
9
样例解释
样例中将模块 1 拆分为模块 2 和模块 3,再将模块 2 拆分为模块 4 和模块 5,代价为 3 · 3 = 9。
数据范围
对于所有测试点,\(1 ≤ n ≤ 10^5,0 ≤ w_i ≤ 10^9,w_i ≤ w_{f_i}\)

测试点 \(n ≤\) \(w_i ≤\)
1 ∼ 2 \(20\) \(10^9\)
3 ∼ 4 \(500\) \(10^9\)
5 ∼ 7 \(10^5\) \(100\)
8 ∼ 10 \(10^5\) \(10^9\)

两个数相乘,我们可以尝试枚举一个,另一个用贪心求。
w数组明显可以离散化,所以把它离散化。我们有两个思路,要不求只有\(x\)个数时所有数最大值最小是多少,要不求最大值\(\le x\)的时候最少有多少个数。第一个思路走不下去,考虑第二个思路。
离散化后,我们枚举最大值,例如现在是小于等于\(x\)的最少数量,那么很容易发现,应该是如果还存在大于\(x\)的点,那么就要把他给拆了。由于\(w_i ≤ w_{f_i}\),所以我们把所有\(w\)从大到小枚举,每一次看现在还存在的点里面有没有大于\(w_i\)的,如果有就拆了,拆完后用最大值乘上存在的点的数量。我们具体可以使用堆实现,如果堆中的最大值大于\(w_i\),那么就把它拆开,拆出来的点放入堆中,可以达到\(O(nlogn)\)的复杂度。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int lsh[N],w[N],hd[N],fth,n;
long long ans=1e18;
struct edge{
	int v,nxt;
}e[N];
struct node{
	int x,w;
	bool operator<(const node&n)const{
		return w<n.w;
	}
};
priority_queue<node>q;
void add_edge(int u,int v)
{
	e[v]=(edge){v,hd[u]};
	hd[u]=v;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",w+i),lsh[i]=w[i];
	for(int i=2;i<=n;i++)
		scanf("%d",&fth),add_edge(fth,i);
	sort(lsh+1,lsh+n+1);
	for(int i=1;i<=n;i++)
		w[i]=lower_bound(lsh+1,lsh+n+1,w[i])-lsh;
	q.push((node){1,w[1]});
	for(int i=n;i>=1;i--)//枚举点权
	{
		while(q.top().w>i&&hd[q.top().x])
		{
			for(int i=hd[q.top().x];i;i=e[i].nxt)
				q.push((node){e[i].v,w[e[i].v]});
			q.pop();
		}
		if(q.top().w<=i)
			ans=min(ans,1LL*lsh[i]*(long long)q.size());
	} 
	printf("%lld",ans);
	return 0;
}
posted @ 2022-04-27 18:06  灰鲭鲨  阅读(64)  评论(0编辑  收藏  举报