BOJ 23836 - 어떤 우유의 배달목록 (Hard)

image.png

트리에 등차수열을 끼얹는 연산을 해야되는데,

우선 트리가 아닌 1차원 배열이라면 어떻게 구현할 수 있을지 생각해보자.

이건 BOJ 17353 이 문제다.

[L,R][L, R] 에 1부터 시작하고 RL+1R-L+1 로 끝나는 등차수열을 더한다.

일단 [L,R][L, R] 구간에 1씩 더해주고 R+1R+1(RL+1)-(R-L+1) 을 더해준다.

그러면 i=0R\displaystyle \sum_{i=0}^{R}RRRL+1R-L+1 이 더해진 값을 얻어올 수 있다.

이걸 트리에 그대로 적용시켜보자.

HLD를 이용하면 uvu \leftrightarrow v 는 여러개의 간선 체인(그룹)으로 나뉜다.

이를 G1,G2,G_1, G_2, \dots 라고 하자.

uLCA(u,v)vu \to LCA(u, v) \to v 의 경로에서 uuLCA(u,v)LCA(u, v) 사이에 있는 그룹 GG에는 이 연산을 거꾸로 해주어야 한다.

그룹 G1G_1 가장 위 노드 HG1H_{G_1} 에서 uu 까지의 노드의 개수가 kk개라면,

HG1k1u0 \begin{aligned} H_{G_1}& \rightarrow k-1\\ &\cdots\\ u &\rightarrow 0 \end{aligned}

와 같이 값이 각각 더해져야 한다. 이를 minus path 라고 하자.

이제 그룹이 LCALCA를 지났다고 한다면, 배열에서 하던거랑 똑같이 11 씩 더해주고 R+1R+1 에 값을 빼주면 된다.

이를 plus path라 하자.

주의할건, 계속 0k10 \cdots k-1 만 더해주는게 아니라 이전 그룹의 개수를 고려해주어야 하기 때문에, 누적으로 합을 업데이트 하면서 이번에 들어갈 kk 가 어떤건지 결정해야 한다.

image.png

빨간색이 트리에서 무거운 간선이라고 하자.

그럼 head[u]head[v] 가 같지 않을 때 까지 uv 를 위로 올려보내면 저 상황에선 v 가 먼저 LCA에 도착한다.

이 문제에선 uvswap 하면서 트리를 이동하는것을 지양하는것이 좋다.

순서가 중요하기 때문이다.

그래서 대략적으로 update 함수만 좀 보자면,

void update_path(int a, int b) {  
  
   vector<pi> minus_path, plus_path;  
  
   while (head[a] ^ head[b]) {  
      if (depth[head[a]] > depth[head[b]]) {  
         minus_path.pb({in[head[a]], in[a]});  
         a = par[head[a]];  
      } else {  
         plus_path.pb({in[head[b]], in[b]});  
         b = par[head[b]];  
      }  
   }  
  
   if (depth[a] < depth[b]) {  
      plus_path.pb({in[a], in[b]});  
   } else {  
      minus_path.pb({in[b], in[a]});  
   }  
   reverse(all(plus_path));  
  
   int next_k = 0;  
  
   for (auto&[l, r]: minus_path) {  
      int len = r - l + 1;  
      next_k += r - l + 1;  
      seg.update(l, r, -1);  
      seg.update(l, l, next_k);  
      seg.update(r + 1, r + 1, -next_k + len);  
   }  
   for (auto&[l, r]: plus_path) {  
      int len = r - l + 1;  
      seg.update(l, r, 1);  
      seg.update(l, l, next_k - 1);  
      seg.update(r + 1, r + 1, -(next_k - 1) - (len));  
      next_k += len;  
   }  
}

처럼 구현했더니 맞았다.

Tags:

Categories:

Updated:

Comments