📅  最后修改于: 2023-12-03 15:28:47.773000             🧑  作者: Mango
本题为 门|门 CS 1999 第 32 题,需要设计一个算法解决某个数列的问题。题目难度为省选/NOI-。
在一个长度为 n(n<=1e5) 的序列中,两个数之间可能存在多组有序数对。例如序列 [1, 2, 2, 3] 中,(1, 2),(2, 3),(1, 3),(2, 4) 为有序数对。现在给出了所有这样的数对,需要你求出某个数在这个序列中出现的次数。
第一行一个正整数 n。
接下来 m 行,每行两个整数 x 和 y,表示 x 和 y 之间存在有序数对。
最后一行一个整数 q,表示询问次数。
接下来 q 行,每行一个整数 x,表示询问 x 在序列中出现的次数。
对于每个询问,输出一行一个整数,表示询问数在序列中出现的次数。
4
1 2
2 3
1 3
2 4
3
1
2
3
2
3
1
本题是一道比较典型的数据结构题,需要用到离线算法,将询问与修改操作分开处理。
在题目描述中已经给出了正确的观察结论:两个数之间可能存在多组有序数对。
因此,我们可以预处理出每个数及其所有“后继”出现的次数。这里的“后继”指的是后面比它大的所有数。考虑到本题中的数很大,我们可以将原序列的每个位置对应一个离散化过的编号,这样可以有效地缩小数组大小,提高效率。
预处理完后,我们对每个询问 x,统计一下它的所有后继中有多少是 y,并输出 y 的次数即可。复杂度为 O(nlogn+qlogn)。
def find(x: int) -> int:
"""
返回 x 在离散化后的数列中的下标
"""
return bisect_left(keys, x)
n = int(input())
edges = defaultdict(list)
unique_keys = set()
# 预处理
for i in range(n):
a, b = map(int, input().split())
unique_keys.add(a)
unique_keys.add(b)
a = find(a)
b = find(b)
edges[a].append(b)
# 离散化
keys = sorted(unique_keys)
for i in range(len(keys)):
for j in range(len(edges[i])):
edges[i][j] = bisect_left(keys, keys[edges[i][j]])
suff = [0]*len(keys)
for i in range(len(keys)-2, -1, -1):
suff[i] = suff[i+1] + len(edges[i])
q = int(input())
# 处理询问
for i in range(q):
x = find(int(input()))
print(suff[x])
以上是 Python 语言的代码示例,其中使用到了标准库里的 bisect_left 和 defaultdict 函数。