1. 问题描述:
达尔星有 n 个强大的下级战士,编号 1∼n。其中第 i 名战士的战斗力为 ri。战士 a 可以成为战士 b 的战斗导师,当且仅当 ra > rb 且两人之间不存在矛盾。给定每个战士的战斗力值以及战士之间存在的 k 对矛盾关系。请你计算,每个战士可以成为多少战士的战斗导师。
输入格式
第一行包含两个整数 n 和 k。第二行包含 n 个整数 r1,r2,…,rn。接下来 k 行,每行包含两个整数 x,y,表示战士 x 和战士 y 之间存在矛盾。同一对矛盾关系不会在输入中重复给出,即出现了 x,y 以后,后面就不会再次出现 x,y 或 y,x。
输出格式
共一行,n 个整数,表示每个战士可以作为战斗导师的战士数量。
数据范围
前三个测试点满足,2 ≤ n ≤ 10,0 ≤ k ≤ 10。
所有测试点满足,2 ≤ n ≤ 2 × 10 ^ 5,0 ≤ k ≤ min(2 × 10 ^ 5,n(n − 1) * 2),1 ≤ ri ≤ 10 ^ 9,1 ≤ x < y ≤n,x ≠ y。
输入样例:
4 2
10 4 10 15
1 2
4 3
输出样例:
0 0 1 2
来源:https://www.acwing.com/problem/content/description/4004/
2. 思路分析:
分析题目可以知道我们考虑当前的战士ai是其他多少个战士的导师,需要满足什么样的条件呢?我们可以考虑下面两个问题:
- 有多少个战士的战斗力小于ra
- 小于ra的数中有多少个是矛盾的
对于第一个问题我们可以使用二分或者双指针找到第一个小于等于ai的位置,对于第二个问题我们可以使用一个count数组来记录每一个战士的矛盾关系,对于战士x,y,如果他们有矛盾我们将矛盾记录到编号较大的战士对应的count位置,这样第一个问题的结果减去第二个问题的结果就是答案。
3. 代码如下:
from typing import List
class Solution:
# 在a中查找小于等于x的第一个位置
def binarySearch(self, x: int, a: List[int]):
l, r = 0, len(a) - 1
while l < r:
mid = l + r >> 1
if a[mid] >= x:
r = mid
else:
l = mid + 1
return r
def process(self):
n, m = map(int, input().split())
a = list(map(int, input().split()))
# 因为后面需要二分所以需要拷贝a的副本到b中
b = a[:]
N = 3 * 10 ** 5
# count用来记录某个点矛盾的数量
count = [0] * N
b.sort()
# 将矛盾的数目记录在count中
for i in range(m):
x, y = map(int, input().split())
if a[x - 1] > a[y - 1]:
count[x] += 1
elif a[x - 1] < a[y - 1]:
count[y] += 1
# 枚举所有的战士判断当前的战士是其他多少个战士的导师
for i in range(1, n + 1):
x = a[i - 1]
k = self.binarySearch(x, b)
print(k - count[i], end=" ")
if __name__ == '__main__':
Solution().process()