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

Автор lrvideckis, история, 21 месяц назад, По-английски

Hi Codeforces! If you calculate midpoint like

int get_midpoint(int l, int r) {//[l, r)
	int pow_2 = 1 << __lg(r-l);//bit_floor(unsigned(r-l));
	return min(l + pow_2, r - pow_2/2);
}

then your segment tree requires only $$$2 \times n$$$ memory.

test
proof

I was inspired by ecnerwala's in_order_layout https://github.com/ecnerwala/cp-book/blob/master/src/seg_tree.hpp

I'll be waiting for some comment "It's well known in china since 2007" 😂

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

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

It's well known in china since 2007

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

Thats cool, you're decomposing the segtree into perfect binary trees, not actually caring if the sizes are the same. It gives me some new intuition on the subject.

»
21 месяц назад, # |
  Проголосовать: нравится +5 Проголосовать: не нравится
»
21 месяц назад, # |
  Проголосовать: нравится -20 Проголосовать: не нравится

Segment tree is always 2n memory. I don't get what is new...

  • »
    »
    21 месяц назад, # ^ |
    Rev. 2   Проголосовать: нравится -14 Проголосовать: не нравится

    I think recursion makes it nlogn. Edit: why did I get downvoted? I'm probably wrong so can you point out my mistake instead of downvoting?

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

    Most implementations take 4n memory.

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

In fact you can label [l, r] with (l + r | (l != r)), the labels also lay in [2, 2n]

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

You can do this also: let the root be the node $$$0$$$ and let the neighbors for any node $$$x$$$ be $$$x + 1$$$ for the left child, and $$$x + 2(m - l + 1)$$$ for the right child (where $$$[l, r] $$$ is the range which node $$$x$$$ is responsible for, and $$$m$$$ is $$$(l + r) / 2$$$). Also, this is exactly the DFS traversal order of the segment tree.

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

    That's a really cool trick. It should also slightly improve cache hits when going to the left son (although not by a large amount). This is how tourist's segment tree is implemented, btw.

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

This trick is actually pretty cool. I played around with this for a while and got AC a sweepline problem that I got MLE weeks ago. With that said, is there any way, any more tricks that could make this thing faster? Like, I benchmark this method of choosing mid-point, versus the classic method and the latter is around 20% faster, despite consuming twice as much memory (probably because the old method divide the segment into half, making the $$$log$$$ constant per query smaller). Is there any kind of recursive segment tree implementation that is both fast and memory-efficient at the same time?