【问题标题】:Element rotation in segment tree [closed]段树中的元素旋转[关闭]
【发布时间】:2014-10-02 19:38:37
【问题描述】:

给定一个数组 A,其中有 N 个数字(全为正数且包含小于 或等于 4 位),支持 2 种查询。那里 总共有 M 个查询。

  1. 通过K更新由索引L,R(包括两者)给出的范围。
  2. 返回 L,R(包括两者)给定范围内的最大元素。

更新数字 K 次意味着旋转数字 K 次。

例如1234转成2341

905转成059,059转成590。

注意:059 和 59 是不同的数字。 59转95。

给定的数组元素没有前导零

约束:

0 艾

1 N

1 M

0 K

我想到了一个分段树,其中树节点存储它们包含的范围的旋转次数。我使用惰性传播实现了这一点,但也使用惰性传播,我的查询实现在最坏的情况下需要 O(N) 时间,这会导致 TIME LIMIT EXCEEDED。

谁能提出一个更快的方法?

我是否缺少数组或结构的某些属性?

【问题讨论】:

  • 问题在哪里?
  • 为什么要删除问题?

标签: algorithm data-structures segment-tree lazy-propagation


【解决方案1】:

您存储旋转次数的想法是正确的。
以下是如何使它更胖(O(log N)per 查询)。
1)节点结构定义:

class Node:
    int shift = 0 //number of rotations
    int max[12] //maximum value for shift = 0..11
    Node left_child //the left child of this node
    Node right_child //the right child of this node

2)传播:

void propagate(Node node):
    node.left_child.shift += node.shift
    node.left_child.shift %= 12
    node.right_child.shift += node.shift
    node.right_child.shift %= 12
    node.shift = 0
    for i = 0..11:
        node.max[i] = max(get_max(node.left_child, i), 
                          get_max(node.right_child, i))

int get_max(Node node, int shift):
     return node.max[(shift + node.shift) % 12]

3)更新和获取操作可以像传统的线段树一样实现。

为什么它工作得很快?因为propagate 不是递归的。仅在回答查询时在树遍历期间访问的那些节点调用它。并且每个查询只有O(log N) 这样的节点(由于段树的属性)。

为什么要使用常数 12?因为lcm(1, 2, 3, 4) = 12.(1, 2, 3, 4 是每个数组元素的可能位数)。

【讨论】:

  • @gaurav1199 没有。访问节点时调用它即可。更改向下传播。
猜你喜欢
  • 1970-01-01
  • 2021-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多