안녕하세요. 오늘은 GCD값을 구할 거예요.
https://www.acmicpc.net/problem/12858
gcd의 성질부터 알아봅시다.
gcd(a,b,c,d,....)는 gcd(a,b-a,c-b,d-c,....)와 동일합니다.
즉, gcd값을 알려면 arr의 값과 arr의 차의 값을 알아야합니다. 여기서 주의할 점은 arr는 tree값이 합으로 저장이 되지만 arr의 차는 tree값이 gcd로 저장이 됩니다. 바로바로 꺼내쓸 수 있게 말이죠.
이때 수를 바꾸는 쿼리가 있으면 arr는 구간이 바뀌므로 lazyprop을 써야합니다. 하지만 arr의 차는 바뀌는 부분이 딱 두 군데 있으므로 그냥 함수 두번 써주면 됩니다.
이제 세그트리 두개를 구현만 잘하면 됩니다.
#include <iostream>
#include <vector>
#include <algorithm>
#define ll long long
using namespace std;
ll tree[404040] = { 0 }, lazy[404040] = { 0 }, arr[101010] = { 0 };
ll init(ll s, ll e, ll node)
{
if (s == e) return tree[node] = arr[s];
ll mid = (s + e) / 2;
return tree[node] = init(s, mid, node * 2) + init(mid + 1, e, node * 2 + 1);
}
void pp(ll s, ll e, ll node)
{
if (lazy[node])
{
tree[node] += lazy[node];
if (s != e)
{
lazy[node * 2] += lazy[node];
lazy[node * 2 + 1] += lazy[node];
}
lazy[node] = 0;
}
}
ll find(ll s, ll e, ll node, ll idx) //idx번지에 있는 값 찾기
{
pp(s, e, node);
if (e < idx || idx < s) return 0;
if (s == e) return tree[node];
ll mid = (s + e) / 2;
return find(s, mid, node * 2, idx) + find(mid + 1, e, node * 2 + 1, idx);
}
void change(ll s, ll e, ll node, ll l, ll r, ll val)
{
pp(s, e, node);
if (e < l || r < s) return;
if (l <= s && e <= r)
{
lazy[node] = val;
pp(s, e, node);
return;
}
ll mid = (s + e) / 2;
change(s, mid, node * 2, l, r, val);
change(mid + 1, e, node * 2 + 1, l, r, val);
tree[node] = tree[node * 2] + tree[node * 2 + 1];
}
ll GCD_tree[404040] = { 0 }, GCD_arr[404040];
ll gcd(ll x, ll y) { return ((y) ? gcd(y, x % y) : x); }
ll GCD_init(ll s, ll e, ll node)
{
if (s == e) return GCD_tree[node] = GCD_arr[s];
ll mid = (s + e) / 2;
return GCD_tree[node] = gcd(GCD_init(s, mid, node * 2), GCD_init(mid + 1, e, node * 2 + 1));
}
ll GCD(ll s, ll e, ll node, ll l, ll r)
{
if (e < l || r < s) return 0;
if (l <= s && e <= r) return GCD_tree[node];
ll mid = (s + e) / 2;
return gcd(GCD(s, mid, node * 2, l, r), GCD(mid + 1, e, node * 2 + 1, l, r));
}
void GCD_change(ll s, ll e, ll node, ll idx, ll val) //idx번지에 있는 값을 val만큼 바꾸기
{
if (e < idx || idx < s) return;
if (s == e)
{
GCD_tree[node] += val;
return;
}
ll mid = (s + e) / 2;
GCD_change(s, mid, node * 2, idx, val);
GCD_change(mid + 1, e, node * 2 + 1, idx, val);
GCD_tree[node] = gcd(GCD_tree[node * 2], GCD_tree[node * 2 + 1]);
}
int main(void)
{
ios_base::sync_with_stdio(false); cin.tie(NULL);
ll N, i, Q, t, a, b;
cin >> N;
for (i = 1; i <= N; i++)
{
cin >> arr[i];
if (i >= 2) GCD_arr[i - 1] = arr[i] - arr[i - 1];
}
init(1, N, 1); GCD_init(1, N, 1);
cin >> Q;
for (i = 1; i <= Q; i++)
{
cin >> t >> a >> b;
if (t == 0)
{
if (a == b) cout << find(1, N, 1, a);
else cout << abs(gcd(find(1, N, 1, a), GCD(1, N, 1, a, b - 1)));
cout << "\n";
}
else
{
change(1, N, 1, a, b, t);
GCD_change(1, N, 1, a - 1, t);
GCD_change(1, N, 1, b, -t);
}
}
}
감사합니다.