📜  门|门 CS 1999 |第 32 题(1)

📅  最后修改于: 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 函数。