📜  门| GATE-CS-2015(套装2)|第 65 题(1)

📅  最后修改于: 2023-12-03 15:12:42.766000             🧑  作者: Mango

门| GATE-CS-2015(套装2)|第 65 题

这是 GATE-CS-2015(套装2)第 65 题。本题考查了程序员对数据结构的理解和运用。以下是本题的详细信息和解答。

题目描述

有一个数列 a1, a2, ..., an。你需要设计一种数据结构和两种操作:

  • 询问区间[k, l]中,第 k 大的数。
  • 更新数列中位置 i 的值。
数据约定
  • 数据范围: $1 \leq n, q \leq 10^5$
  • 每个数的绝对值不会超过 $10^9$。
解答思路

显然,本题是一道查询和修改综合的题目,考虑利用一棵数据结构维护数列。由于我们需要查询区间第 k 大的数,可以考虑利用堆实现。

查询第k大的数

我们考虑建立一棵以值为关键字的最大堆。在查询操作时,我们先向堆中插入数列 a 中的前 k-1 个元素,然后向后逐一插入 a[k], a[k+1] ...... a[l]。每插入一个数,我们取出堆顶元素,判断它是否在区间[k,l]中,如果在,那么它就是区间[k,l]中第 k 大的数。

修改位置i的值

修改操作比较简单,我们只需要找到位置i所对应的元素,并将其改为新的值。然后,我们需要重新调整堆以保持堆的性质。

复杂度分析

由于查询操作要遍历区间,插入操作要插入 n 个元素,每次插入需要 $O(\log n)$ 的时间复杂度。因此,本题总的时间复杂度为 $O(q \log n)$。

代码实现
import heapq

class Query(object):
    def __init__(self, k, l):
        self.k = k
        self.l = l

    def __cmp__(self, other):
        return self.k - other.k

class QueryHeap(object):
    def __init__(self):
        self.heap = []
        self.index_map = {}

    def add_query(self, query):
        index = len(self.heap)
        self.heap.append(query)
        self.index_map[query] = index
        self.bubble_up(index)

    def update_query(self, query, new_k):
        index = self.index_map[query]
        query.k = new_k
        self.bubble_up(index)

    def pop(self):
        last_query = self.heap.pop()
        if self.heap:
            query = self.heap[0]
            self.heap[0] = last_query
            self.index_map[last_query] = 0
            self.sink_down(0)
        else:
            query = last_query
        del self.index_map[query]
        return query

    def bubble_up(self, index):
        while index > 0:
            parent_index = (index - 1) // 2
            if self.heap[parent_index] < self.heap[index]:
                self.swap(index, parent_index)
                index = parent_index
            else:
                break

    def sink_down(self, index):
        end_index = len(self.heap)
        while True:
            left_child_index = 2*index + 1
            right_child_index = 2*index + 2
            child_index = None

            if left_child_index < end_index:
                child_index = left_child_index

            if right_child_index < end_index and self.heap[right_child_index] < self.heap[left_child_index]:
                child_index = right_child_index

            if child_index is not None and self.heap[child_index] > self.heap[index]:
                self.swap(index, child_index)
                index = child_index
            else:
                break

    def swap(self, index1, index2):
        query1 = self.heap[index1]
        query2 = self.heap[index2]
        self.heap[index1], self.heap[index2] = query2, query1
        self.index_map[query1], self.index_map[query2] = index2, index1

class Interval(object):
    def __init__(self, left, right):
        self.left = left
        self.right = right

    def __cmp__(self, other):
        return self.left - other.left

class IntervalTree(object):
    def __init__(self, intervals):
        self.root = self.build_tree(intervals)

    def build_tree(self, intervals):
        if not intervals:
            return None

        intervals = sorted(intervals)
        mid_index = len(intervals) // 2
        mid_value = intervals[mid_index]
        left_child = self.build_tree(intervals[:mid_index])
        right_child = self.build_tree(intervals[mid_index+1:])

        node = TreeNode(mid_value, left_child, right_child)
        if left_child:
            left_child.parent = node
        if right_child:
            right_child.parent = node
        return node

    def query(self, k, l):
        heap = QueryHeap()
        node = self.root
        while node:
            if node.value.left <= l:
                if node.value.right >= k:
                    if node.left_child:
                        heap.add_query(Query(k, node.value.right))
                    if node.right_child:
                        heap.add_query(Query(node.value.left, l))
                    break
                elif node.value.right < k:
                    node = node.right_child
            else:
                node = node.left_child

        result = None
        for _ in range(k):
            query = heap.pop()
            result = query.k
            if _ == k - 1:
                break
            if query.l >= l:
                if query.k + 1<= result:
                    break
                heap.add_query(Query(result + 1, query.l))
            if query.k + 1 == heap.heap[0].k:
                break

        return result

    def update(self, index, new_value):
        node = self.root
        while node:
            if node.value.left <= index <= node.value.right:
                node.value = Interval(index, index)
                node.update_max_leaf()
                break
            elif index < node.value.left:
                node = node.left_child
            else:
                node = node.right_child

def build_interval_tree(n):
    intervals = [Interval(i + 1, i + 1) for i in range(n)]
    return IntervalTree(intervals)

class TreeNode(object):
    def __init__(self, value, left_child, right_child):
        self.value = value
        self.left_child = left_child
        self.right_child = right_child
        self.parent = None
        self.max_leaf = self.value.right

        if self.left_child:
            self.max_leaf = max(self.max_leaf, self.left_child.max_leaf)
            self.left_child.parent = self
        if self.right_child:
            self.max_leaf = max(self.max_leaf, self.right_child.max_leaf)
            self.right_child.parent = self

    def update_max_leaf(self):
        node = self.parent
        while node:
            node.max_leaf = max(node.left_child.max_leaf, node.right_child.max_leaf)
            node = node.parent

def test():
    n = 5
    a = [0, 3, 4, 2, 1]
    q = [
        (1, 3, 2),
        (2, 2, 3),
        (1, 2, 4),
        (2, 4, 4)
    ]

    tree = build_interval_tree(n)

    for i in range(n):
        tree.update(i+1, a[i])

    for op in q:
        if op[0] == 1:
            result = tree.query(op[1], op[2])
            print('Query [{}-{}]: {}'.format(op[1], op[2], result))
        else:
            index, new_value = op[1], op[2]
            tree.update(index, new_value)

            new_result = tree.query(2, 4)
            print('After update [{}]: Query [2-4]: {}'.format(index, new_result))

test()

以上是本题的解答,欢迎阅读。