Блог пользователя amiralisalimi

Автор amiralisalimi, 4 года назад, По-английски

We have an array of numbers and we are supposed to do the following queries on it:

  1. Add number x to all elements on the subarray with indices [ L, R ] of the array.
  2. Query for number of elements less than number x of the whole array.

Note that x is given in each query and is not fixed.

I have a solution with time complexity $$$O(q \cdot log(n) \cdot \sqrt n)$$$ using Square root decomposition (Storing BST for each sqrt block or just sorted subarray in each block) where $$$n$$$ is the size of the array and $$$q$$$ is the number of the queries. However for constraints $$$n, q < 1e5$$$ with time limit of 2 seconds this is not efficient enough. So how to solve it on these constraints?

  • Проголосовать: нравится
  • +66
  • Проголосовать: не нравится

»
4 года назад, # |
  Проголосовать: нравится -28 Проголосовать: не нравится

MO's algo would be helpful..ig

»
4 года назад, # |
  Проголосовать: нравится -16 Проголосовать: не нравится

Segment Tree Beats is the way to go

»
4 года назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

Can you provide the problem link?

»
4 года назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

Is x fixed? And how large/small can it be?

»
4 года назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

Merge Sort Tree with lazy propagation?

  • »
    »
    4 года назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    merge sort tree will not work in case of updates

    • »
      »
      »
      4 года назад, # ^ |
        Проголосовать: нравится +11 Проголосовать: не нравится

      It works with single element updates (with changing sorted arrays to BSTs), but not with interval updates.

»
4 года назад, # |
  Проголосовать: нравится +22 Проголосовать: не нравится

Use radix sort, then you can solve it in $$$O(n\sqrt{n\log n})$$$ lol

  • »
    »
    4 года назад, # ^ |
      Проголосовать: нравится +3 Проголосовать: не нравится

    Could you please explain more about your solution? It would be nice if you provide some links to read more and some problems on the algorithm.

    • »
      »
      »
      4 года назад, # ^ |
      Rev. 3   Проголосовать: нравится +17 Проголосовать: не нравится

      You don't need BST, you can store simple sorted array for each block and rebuild it completly when some elements in block are changed. Then, if you manage to make this rebuild in $$$O(blocksize)$$$ (not in $$$O(blocksize \cdot \log{blocksize})$$$, you can set block size to such value that total complexity will became $$$O(\sqrt{n \log{n}})$$$.

      To do this he proposed you to use radix sort, but actually you can achieve it more simple. Just use previous version of sorted array to get separately two sorted sequences of added and non-added elements and then merge this two sequences into one. All this is done by linear time.

      • »
        »
        »
        »
        4 года назад, # ^ |
        Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

        Nice trick on merging two sorted arrays instead of rebuilding! But still additional log is needed for the second query.

        • »
          »
          »
          »
          »
          4 года назад, # ^ |
          Rev. 2   Проголосовать: нравится +16 Проголосовать: не нравится

          Yes, but it allows us to set block size equal to $$$\sqrt{n \log n}$$$, so second query is performed in $$$O(\frac{n}{blocksize} \log blocksize) = O(\frac{n}{\sqrt{n \log n}} \log n) = O(\sqrt{n \log n})$$$. And first query is performed in $$$O(blocksize + \frac{n}{blocksize})$$$, which is also $$$O(\sqrt{n \log n})$$$. Without it you can't do this.

»
4 года назад, # |
Rev. 3   Проголосовать: нравится +21 Проголосовать: не нравится

Anyway, I think $$$2$$$ seconds is enough to let the code with the time complexity $$$O(n\sqrt{n\log n})$$$ while $$$n = 10^5$$$ pass on Codeforces. Just have a look at 551E - GukiZ и GukiZiana.

»
4 года назад, # |
  Проголосовать: нравится -16 Проголосовать: не нравится

The same problem with single position update can be solved by persistent segment trees (check this). I believe it can be modified for an interval update

»
4 года назад, # |
  Проголосовать: нравится +12 Проголосовать: не нравится

You can make it $$$O((n+q)\sqrt{n})$$$ with fractional cascading but it wasn't really faster than the $$$O((n+q)\sqrt{n\log{n}})$$$ solution in my tests.

There probably isn't a much faster way because a much faster way would mean a much faster (than $$$O(n^3)$$$) way to solve the all-pairs shortest paths problem.

  • »
    »
    4 года назад, # ^ |
      Проголосовать: нравится +14 Проголосовать: не нравится

    What is the reduction to the all-pairs shortest paths problem?

    • »
      »
      »
      4 года назад, # ^ |
        Проголосовать: нравится +23 Проголосовать: не нравится

      Here's a reduction from min-plus matrix multiplication, which can be used to solve all-pairs shortest paths:

      Let $$$M$$$ be a number much larger than the elements. The variables $$$i$$$,$$$j$$$ and $$$k$$$ go up to $$$\sqrt{n}$$$.

      Divide the array into $$$\sqrt{n}$$$ blocks of equal size. Set the $$$j$$$th number of the $$$i$$$th block to $$$a_{ij}+jM$$$.

      Do $$$\sqrt{n}$$$ iterations of the following, resetting after each iteration. On the $$$k$$$th iteration, for each $$$i$$$, add $$$b_{ki}$$$ to the $$$i$$$ block. Then, for each $$$j$$$, query $$$Mj+c_{kj}$$$ to determine the number of $$$i$$$ such that $$$a_{ij}+b_{ki}\ge c_{kj}$$$.

      We only care if some $$$i$$$ exists, so we can repeat the entire construction to binary search for all $$$c_{kj}=\min_i(a_{ij}+b_{ki})$$$ in parallel.

      We've used $$$O(n\log{M})$$$ operations to compute the min-plus matrix product of two $$$\sqrt{n}$$$ by $$$\sqrt{n}$$$ matrices.

  • »
    »
    4 года назад, # ^ |
      Проголосовать: нравится +1 Проголосовать: не нравится

    Can you explain how to do this with fractional cascading? Do you still divide array into blocks of $$$\sqrt n$$$ size?

    • »
      »
      »
      4 года назад, # ^ |
        Проголосовать: нравится +8 Проголосовать: не нравится

      First divide array into blocks of $$$\sqrt{n}$$$ and keep elements in each block sorted. Then, build something like a segment tree on top of the blocks. Each node will sample every fourth element of its children, so the number of elements per node halves every layer.

      To handle queries, walk down the segment tree to all of its leaves (there are $$$\sqrt{n}$$$ of them) and compute for each node the last element less than $$$x$$$. This can be done in $$$O(1)$$$ per node using the answer from its parent.

      To handle updates, most blocks can get lazily marked. The only ones that can't are the blocks containing the endpoints of the interval and their ancestors in the segment tree. These can be rebuilt in $$$O(\sqrt{n})$$$.

      Here's the code I wrote for this some time ago:

      Code
      • »
        »
        »
        »
        4 года назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится

        Thanks. This "each node will sample every fourth element of its children" is some next level usage of fractional cascading.