O(n) 取得数组中每个元素右边最后一个比它大的元素
题目
2019.9.7,icpc徐州网络赛的E题 XKC's basketball team ,计蒜客上还可以做。
链接:https://nanti.jisuanke.com/t/41387
Input
The first line contains two integers n and m ( 2 ≤ n ≤ 5∗10^5 ,0 ≤ m ≤ 10^9) .
The following line contain n integers W1..Wn(0 ≤ Wi ≤ 10^9) .
Output
A row of n integers separated by spaces , representing the anger of every member .
样例输入
6 13 4 5 6 2 10
样例输出
4 3 2 1 0 -1
题意:
对于数组中的每个元素来说,如果它加上m之后,右边仍然有比它大的数(有多个的话,取距离最远的),这个距离就是我们要的结果,不存在取 -1。所以问题就是,取得数组中每个元素右边最后一个比它大的元素。
思路:
看了 “O(n) 取得数组中每个元素右边第一个比它大的元素” 的思路想到的。
- 建立一个Node (value, index);value是原数组的值 + m,index是对应的索引。(具体的value是什么,视问题而定)
- 建立壹 Node 的 value 值升序的优先级队列。也就是小根堆。
- i = n - 1,开始向前遍历
不断用当前堆顶的value值与arr[i]进行比较,如果堆顶元素小于arr[i],则找到需要找的元素。因为堆顶是最小的元素,如果堆顶大于arr[i],则i--,继续重复当前步骤。
- 直到遍历完成,堆中大概率还会剩下几个(加+m之后,原数组中没有元素比它们大了),这些元素对应的 res 都是 -1 。
1 #include <iostream> 2 #include <queue> 3 #include <stdio.h> 4 using namespace std; 5 6 int arr[500005]; 7 int anger[500005]; 8 9 struct Node { 10 int value, index; 11 Node(int v, int i) :value(v), index(i) {}; 12 bool operator< (const Node& n)const { 13 return n.value < value; 14 } 15 }; 16 priority_queue <Node>pq; 17 18 int main() { 19 int n, m; 20 cin >> n >> m; 21 for (int i = 0; i < n; i++) { 22 scanf("%d", &arr[i]); 23 anger[i] = -1; 24 pq.push(Node(arr[i] + m, i)); 25 } 26 27 for (int i = n - 1; i >= 0; i--) { 28 while (!pq.empty()) { 29 int top = pq.top().value; 30 if (arr[i] >= top) { 31 int index = pq.top().index; 32 pq.pop(); 33 if (i > index) { 34 anger[index] = i - index - 1; 35 } 36 else anger[index] = -1; 37 } 38 else break; 39 } 40 } 41 42 for (int i = 0; i < n; i++) { 43 printf("%d", anger[i]); 44 if (i != n - 1)printf(" "); 45 } 46 47 return 0; 48 }