https://www.acmicpc.net/problem/1280
1280번: 나무 심기
첫째 줄에 나무의 개수 N (2 ≤ N ≤ 200,000)이 주어진다. 둘째 줄부터 N개의 줄에 1번 나무의 좌표부터 차례대로 주어진다. 각각의 좌표는 200,000보다 작은 자연수 또는 0이다.
www.acmicpc.net
문제해설
"펜윅 트리" 를 사용하여 풀었습니다. 입력이 들어왔을때 두가지의 경우를 나누었습니다.
현재 input 이 x 라고 하였을때
case1 : x 보다 좌표값이 큰 나무들
case2 : x 보다 좌표값이 작은 나무들
< case1 >

x보다 작은 값들과의 합은
(x - a) + (x - b) + (x - c) = 3*x - (a + b + c)
즉, (입력보다 작은 점들의 갯수) * (입력좌표) - ( 입력보다 작은 점들의 합 )
으로 나타낼 수 있습니다.
< case2 >

x보다 큰 값들의 합은
(a - x) + (b - x) + (c - x) = (a + b + c) - 3*x
즉,(입력보다 큰 점들의 합) - (입력보다 큰 점들의 갯수) * (입력좌표)
로 나탈낼 수 있습니다.
두가지의 경우를 나누어서
펜윅트를 사용해서
입력좌표보다 큰 값들의 총 갯수, 총 합
입력좌표보다 작은 값들의 총 갯수, 총 갯수
를 구한뒤 문제를 풀 수 있습니다.
(다만 주의할점은, 중간 계산 과정에서 long long 범위에 담기지 않을 수 있음으로, mod 연산을 중간 과정에서도 해줘야합니다 )
전체코드
#include <iostream> #include <vector> #include <stack> #include <queue> #include <algorithm> #include <cmath> #include <string> #include <map> #include <set> using namespace std; #define MAX_N 200000 #define DIV 1000000007 typedef long long ll; ll tree_dist[MAX_N+1]; int tree_cnt[MAX_N+1]; int N; void update_dist(int target, int value) { while (target <= MAX_N) { tree_dist[target] += value; target += (target & -target); } } void update_cnt(int target, int value) { while (target <= MAX_N) { tree_cnt[target] += value; target += (target & -target); } } ll query_dist(int target) { ll ret = 0; while (target >= 1) { ret += tree_dist[target]; target -= (target & -target); } return ret; } int query_cnt(int target) { int ret = 0; while (target >= 1) { ret += tree_cnt[target]; target -= (target & -target); } return ret; } int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int N; cin >> N; ll ret = 1; for (int i = 1; i <= N; i++) { ll tmp = 0; int data; cin >> data; data++; if (i == 1) { update_cnt(data, 1); update_dist(data, data); } else { tmp = (tmp + (query_cnt(data - 1) * data) - (query_dist(data - 1))) % DIV; tmp = (tmp + (query_dist(MAX_N) - query_dist(data)) - (query_cnt(MAX_N) - query_cnt(data)) * data) % DIV;; update_cnt(data, 1); update_dist(data, data); ret = (ret * tmp) % DIV; } } cout << ret % DIV << "\n"; }

'알고리즘 > [C++]BOJ' 카테고리의 다른 글
[백준BOJ] 3006 터보소트 (0) | 2019.10.06 |
---|---|
[백준BOJ] 11658 구간 합 구하기3 (0) | 2019.10.06 |
[백준BOJ] 1507 궁금한 민호 (0) | 2019.10.06 |