구간 업데이트(덧셈)가 있을 때 쿼리마다 구간의 gcd를 구하는 문제이다.
각 구간별 gcd를 세그먼트 트리로 저장하는 일반적인 방법으로는 시간초과가 발생한다. 구간에 수를 더하면 gcd를 다 다시 계산해야하기 때문이다.
수를 더했을 때 gcd를 모두 재계산하는 것을 막기 위해선 gcd(a, b) = gcd(a, a-b)
라는 성질을 활용해야한다. 이 식을 확장하면 gcd(a, b, c, d, e) = gcd(a, |b-a|, |c-b|, |d-c|, |e-d|)
라는 것을 알 수 있다.
세그먼트 트리의 각 노드에서 gcd(|b-a|, |c-b|, |d-c|, |e-d|)
를 관리한다고 했을 때, b, c, d에 x만큼을 더하면 |c-b|
와 |d-c|
의 값은 변하지 않고 양쪽 끝의 |b-a|
, |e-d|
만 갱신해주면 된다. 구간이 아무리 넓더라도 두 개의 리프에 대해서만 gcd를 다시 계산하면 되기 때문에 효율적이다.
구간의 시작인 a에 해당하는 값과, gcd 세그먼트 트리에서 gcd(|b-a|, |c-b|, |d-c|, |e-d|)
에 해당하는 구간 gcd를 가져와서 gcd해주면 각 쿼리의 답을 구할 수 있다. 따라서 구간에 대한 합 연산을 lazy하게 수행하기 위한 lazy seg와, gcd를 저장하는 seg를 구현하면 된다.