※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※

 

이번에 볼 문제는 백준 1615번 문제인 교차개수세기이다.
문제는 아래 링크를 확인하자.

https://www.acmicpc.net/problem/1615 

 

1615번: 교차개수세기

첫 줄에 N과 간선의 개수 M이 주어진다. 그 다음 줄부터 M+1번째 줄까지 두 개의 수(i, j)가 주어지는데 이는 왼쪽 그룹의 i번 정점과 오른쪽 그룹의 j번 정점을 연결하는 간선이 있다는 의미이다.

www.acmicpc.net

주어진 선분들의 교차점의 개수가 몇 개인지 세는 문제이다.

선분들을 1) 왼쪽 노드번호가 작은 것부터, 2) 왼쪽 노드번호가 같은 두 선분이 있다면 오른쪽 노드번호가 작은 것부터 살펴보자.

 

지금 보고있는 선분과 앞서 나온 선분들 사이의 교차점의 개수는 지금 긋는 선분의 오른쪽 노드번호보다 큰 오른쪽 노드번호를 갖는 선분들의 수와 같다는 점을 관찰하자. 앞서나온 선분들의 왼쪽끝은 지금의 선분보다 번호가 작기 때문이다. 같은 경우 교차점은 없기 때문에 고려하지 않는다. 2) 규칙을 잘 생각해보면 알 수 있다.

 

따라서 구간합을 관리하는 세그먼트트리(segment tree)를 이용하면 문제를 해결할 수 있다.

 

아래는 제출한 소스코드이다.

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;

int seg[4097];

void update(int L, int R, int qI) {
	int sI = 1;
	while (L < R) {
		seg[sI]++;
		int mid = (L + R) / 2;
		if (qI <= mid) {
			R = mid;
			sI = sI * 2;
		}
		else {
			L = mid + 1;
			sI = sI * 2 + 1;
		}
	}
	seg[sI]++;
}

int rangesum(int L, int R, int qL, int qR, int sI) {
	if (R < qL || qR < L) return 0;
	if (qL <= L && R <= qR)return seg[sI];
	return rangesum(L, (L + R) / 2, qL, qR, sI * 2) + rangesum((L + R) / 2 + 1, R, qL, qR, sI * 2 + 1);
}

vector<pair<int, int>> pairs;

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);

	int N, M; cin >> N >> M;
	while (M--) {
		int x, y; cin >> x >> y;
		pairs.push_back({ x,y });
	}

	sort(pairs.begin(), pairs.end());

	ll ans = 0;
	for (auto p : pairs) {
		int x = p.second;
		ans += rangesum(1, N, x + 1, N, 1);
		update(1, N, x);
	}

	cout << ans;
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 17609 // C++] 회문  (0) 2021.09.26
[BOJ 2472 // C++] 체인점  (0) 2021.09.25
[BOJ 1017 // C++] 소수 쌍  (0) 2021.09.23
[BOJ 10282 // C++] 해킹  (0) 2021.09.22
[BOJ 5721 // C++] 사탕 줍기 대회  (0) 2021.09.21

+ Recent posts