AllForCode's blog

By AllForCode, history, 5 months ago, In English

I came up with this problem recently but haven't been able to find an efficient approach. Since it's a self-created problem, I don't have official test cases.

Problem Statement

There is a sequence a of n integers. Process q queries given in order. For q-th query, you are given integers l, r (1 <= l <= r <= n) and a integer x.Perform the following in order: Add x for each of a[l], a[l + 1],.., a[r]. Let m = r - l + 1, and b = (b[1], b[2],.., b[m]) = (a[l], a[l + 1],.., a[r]). For array b you need to perform m — 1 operations. For each operation, select two elements x, y from the array, delete them and add elements x + y to the array with a cost of x + y, find the smallest total cost modulo 1e9 + 7. (n <= 1e5, q <= 1e5, |a[i]| <= 1e9)

I can't think of a specific time limit for this problem either, but can you find the quickest way to solve it?

Update : The addition of x to the values ​​from position l to r in the i-th query will apply to all queries from i + 1 onwards, meaning that after query i, array a becomes a = (a[1], a[2], ..., a[l] + x, a[l + 1] + x, a[r] + x, ..., a[n])

Update 2 : Sorry everyone, I mixed things up a bit while explaining my idea. I've just updated the prompt.

  • Vote: I like it
  • +5
  • Vote: I do not like it

»
5 months ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

Auto comment: topic has been updated by AllForCode (previous revision, new revision, compare).

»
5 months ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

Auto comment: topic has been updated by AllForCode (previous revision, new revision, compare).

»
5 months ago, hide # |
Rev. 2  
Vote: I like it 0 Vote: I do not like it

Well, I guess this is lazy segment tree. Please correct me if I'm wrong. Edit: Nevermind, I think I misunderstood the problem.

  • »
    »
    5 months ago, hide # ^ |
    Rev. 2  
    Vote: I like it 0 Vote: I do not like it

    It is, if sort didn't exist. Sorting makes the problem way harder, I could only thought of when there're no updates, then one can use Mo's algorithm to get a time complexity of $$$O(n\sqrt{n}\log(n))$$$.

    • »
      »
      »
      5 months ago, hide # ^ |
      Rev. 3  
      Vote: I like it 0 Vote: I do not like it

      But the sorting part is the most important part of this problem. I wrote the sort this way to simplify the operation. In fact, if I needed to explain it in words, for array b you need to perform m — 1 operations. For each operation, select two elements x, y from the array, delete them and add elements x + y to the array with a cost of x + y, find the smallest total cost modulo 1e9 + 7. After analysis, it is essentially sorting array b and giving ((m — 1) * b[1] + (m — 1) * b[2] + .. + b[m]) % (1e9 + 7)

      • »
        »
        »
        »
        5 months ago, hide # ^ |
         
        Vote: I like it 0 Vote: I do not like it

        After analysis, it is essentially sorting array b and giving ((m — 1) * b[1] + (m — 1) * b[2] + .. + b[m])

        If I understand correctly, it is not. For example, let $$$m = 4$$$ and $$$b[1] = b[2] = b[3] = b[4] = 1$$$. You can select $$$1$$$ and $$$1$$$ twice, each time for a cost of $$$2$$$, and then select $$$2$$$ and $$$2$$$ at the end for a cost of $$$4$$$. The total cost is $$$8$$$, but your formula gives $$$9$$$.

        The optimal way to do this is well-studied and is known as Huffman's algorithm. It is not just a simple sort. I am pretty sure it is hard to compute this on a segment faster than by simply simulating the process, even without range increments.

        • »
          »
          »
          »
          »
          5 months ago, hide # ^ |
           
          Vote: I like it 0 Vote: I do not like it

          Oh, sorry, thank you for pointing that out. I will correct the problem statement.

        • »
          »
          »
          »
          »
          5 months ago, hide # ^ |
           
          Vote: I like it 0 Vote: I do not like it

          So there's no way to optimize this beyond simple simulation? If i were to do it, here’s my approach: I’d push all elements from l to r into a min-priority queue. Starting with Total_Cost = 0, I’d greedily extract the two smallest elements, x and y, then insert their sum x + y back into the queue and update Total_Cost += x + y. After repeating this m — 1 times, the Total_Cost would be the final answer. Does this simulation approach sound correct to you?

»
5 months ago, hide # |
Rev. 2  
Vote: I like it 0 Vote: I do not like it

Below is a solution to a different problem. I thought the sorted array was written back over the original values. I also missed the range addition.

Use square-root decomposition on the array. For each block, store this data structure. To sort a range, merge the data structures of all affected blocks into one, then split it back into blocks. The complexity is $$$\Theta(q \sqrt{n \log n})$$$.

»
5 months ago, hide # |
Rev. 3  
Vote: I like it 0 Vote: I do not like it

Because we add the same $$$x$$$ to all elements for a given range, the ordering in that range will not change. So, for each range, the question becomes finding $$$m \cdot a[l] + (m-1) \cdot a[l+1] + \ldots + 2 \cdot a[r-1] + 1 \cdot a[r]$$$ for the sorted $$$[l,r]$$$ range. Then we can just add $$$\frac{x \cdot m \cdot (m+1)}{2}$$$ to the result.

As yoshi_avx mentioned, the best solution is most probably Mo's and maybe a merge sort tree or segment tree solution, though I didn't find or write a solution yet.

It's also really easy to solve the problem in $$$O(nq \log n)$$$, for small $$$n$$$ and/or $$$q$$$.

O(nq log n) Solution
  • »
    »
    5 months ago, hide # ^ |
    Rev. 2  
    Vote: I like it 0 Vote: I do not like it

    The addition of x to the values ​​from position l to r in the i-th query will apply to all queries from i + 1 onwards, it's not just applied locally in query i.IYou should modify the code to handle these cumulative effects. Besides the formula ((m — 1) * b[1] + (m — 1) * b[2] + .. + b[m]) % MOD, it is m — 1 at b[1].

    • »
      »
      »
      5 months ago, hide # ^ |
       
      Vote: I like it 0 Vote: I do not like it

      Oh yeah true, I don't actually update the array's elements in the code. I wrote that in 5 mins lol let me update it so it's correct.

  • »
    »
    5 months ago, hide # ^ |
     
    Vote: I like it 0 Vote: I do not like it

    adding x on [l, r] doesn't change the ordering of [l, r] but might change the ordering of [l, r+1] (or any range containing elements both in and outside [l, r]).

    e.g. [1, 2, 3, 4, 5] => [11, 12, 13, 14, 5]

    • »
      »
      »
      5 months ago, hide # ^ |
       
      Vote: I like it 0 Vote: I do not like it

      True, I was only saying that as it might help with solving each individual query.

  • »
    »
    5 months ago, hide # ^ |
     
    Vote: I like it 0 Vote: I do not like it

    How do you calculate the contributions when the ranges partially intersects?

»
5 months ago, hide # |
Rev. 6  
Vote: I like it +8 Vote: I do not like it

I have a $$$O(q \cdot n\sqrt{n} \cdot log(\sqrt{n}))$$$ idea which I think can be optimized

The answer to a query can be simplified into:

$$$\sum^{r}_{i=l} (a_i * (x + 1)) - min^{r}_{i=l} b_i$$$

where x is the number of indices $$$j$$$ such that $$$l \le j \le r, j \ne i, a_i \le a_j$$$

So we can do as follows

First we do sqrt decomposition on the array and sort every block

For every query, we go through every block:

  • If the block lies completely in the interval, add x to the lazy value corresponding to that block.

  • Else add x to every element in that block which has an index inside of the interval and sort the block

After updating, we can go through every element, perform binary search on every block to calculate the number of indices $$$j$$$. Finally, we subtract the minimim

»
5 months ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

I doubt it's as efficient a solution as you want, but since no one has said it yet, it can be solved straightforwardly in O(n*log(n)+nq) by maintaining an indexed sorted list: after initial sort, for each query, split into two lists with indices inside range and outside range; add x to each array element in the inside range list and calculate the result directly. Then do O(n) sorted list merge to get our fully sorted list back.