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

Автор tgp07, история, 3 года назад, По-английски

I was working on a problem, and I managed to reduce it to the following question:

Given two arrays of integers a[0], and k[n], perform the following operation n times.

  1. In the ith operation, find the rightmost element in a that is smaller than k[i],

  2. Add k[i] to the right end of a.

  3. Do 1 & 2 n times

I'm trying to use Segment Trees on this, but I'm not able to get the right construction.

Does anyone have a way to do this efficiently(under n^2)?

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

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

If an element is larger than another element and also precedes it we can ignore it, so you can maintain a list of decreasing elements from right to left (Think about it like a stack, but implementation-wise it will probably be better as a vector / deque because of the next step), then perform a binary search on it (pick the biggest that is smaller than K[i])

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

    this! i don't understand why everyone is talking about segment trees when a simple stack would do

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

You can do coordinate compression on all elements in K, then you make a segment tree on array B, where B[x] = latest occurrence of x in array A. So now finding rightmost element in A that is smaller than K[i] becomes a maximum query on range [0; K[i]-1]. After query, update B[K[i]] = i.

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

    This approach is a hidden gem that I really love. Thanks for teaching me this beautiful approach!

    Edit: Did I say something wrong lol?

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

In order to make this O(NlogN) with segment trees, do the following.

  1. Make a SegmentTree with size equal to k.size() + a.size().

  2. At the start, push all elements from A there, and then, when you have to add k[i], call point update on pos = a.size() + i (so make a[a.startSize + i] = k[i])

  3. Then, do the following:

Call recursively from Node V(at the start, this is the node responsible for the whole segment): Consider its two sons

If the right son is v.r and left son is v.l, you can do the following:

if v.r min < k[i], then there exists an element there less than k[i], and you need to only consider that segment (call recursively from v.r) otherwise, call from v.l, as that's where the minimum is

This technique is called descending the Segment Tree

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

    A bit overkill, so I wouldn't recommend for this specific problem, but nonetheless a nice technique to consider!

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

Simple stack dude:)

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

    Would it handle duplicates?

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

      Yes, you need to add a number to the stack only if it is strictly smaller than the top one ( you can look at my comment if you don't understand :) ).

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

Next time, can you post where you got the problem statement from? I know it can be a pain, but it ensures that we are not abetting in cheating from some ongoing contest.

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

    Oh, didn't know codeforces is used (Not in this post I assume) to cheat in other websites, thanks for letting me know, will be more careful next time!

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

    Here: https://codeforces.net/problemset/problem/1450/D. Also, my observation was wrong lol.

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

      How do you prove that this problem isn't binary searchable? Like if you can make a permutation with the first K, you can also make one with the first K + 1?

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

        Actually, the observation helped a lot lol. I got it AC using segment tree and prefix sums.

        Also, I'm not sure your observation is correct(I thought so too). Look at one of the example tc's: 1011. Is this binary searchable?

        My submission: 153769266.

        I used EnDeRBeaT's approach because that was honestly the easiest to understand lol.