이진 트리에서 u,v  (u<v)u, v~~(u<v) 가 있을 때, vvuu의 왼쪽 자식인지, 오른쪽 자식인지 아님 둘다 아닌지를 판단해보자.

이건 당연히 vv 부터 위로 타고 올라가면 logN\log N 으로 구할 수 있지만, O(1)O(1) 에 구하는 방법을 알아보자.

image.png

일단 uuvv의 트리에서의 레벨은 아는 상태라고 하자.

11번 노드의 레벨을 00 으로 둔다.

레벨은 대략 다음과 같이 구할 수 있다.

int get_level(ll i) {  
   int level = 0;  
   ll cur = 1;  
   while (cur * 2 <= i) level++, cur *= 2;  
   return level;  
}

사실 이건 log2i\log_2 i 인데, 실수 오차가 없도록 구현한 것이다.

일단 lvu<lvvlv_u < lv_v 라 하자. 아니라면 자식이 될 수 없다.

높이차이 d=lvvlvud=lv_v-lv_u 를 정의한다.

u2du \cdot 2^dlvvlv_v 레벨에서 uu 의 자식이 될 수 있는 가장 작은 노드이다.

그런데 lvvlv_v 레벨에서 uu 의 자식이 될 수 있는 노드의 개수는 2d2^d 개이므로,

결국 uulvvlv_v 에서의 왼쪽 자식이 되려면

[u2d,u2d+2d1) [u \cdot 2^d, u \cdot 2^d+2^{d-1})

범위에 있어야 하고, 오른쪽 자식이 되려면

[u2d+2d1,(u+1)2d) [u \cdot 2^d+2^{d-1},(u+1)\cdot 2^d)

에 있어야 한다.

즉, u2dv<u2d+2d1u \cdot 2^d \le v < u \cdot 2^d+2^{d-1} 이라면 vvuu의 왼쪽 자식의 서브트리에 존재한다.

ll L = cur * pw2[d];  
ll M = left + pw2[D - 1];
ll R = (cur + 1) * pw2[d];
if (L <= i && i < M) {
  // 왼쪽 자식
} else if(M <= i && i < R) {  
  // 오른쪽 자식
}

Tags:

Categories:

Updated:

Comments