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

 

이번에 볼 문제는 백준 10565번 문제인 Salary Inequity이다.
문제는 아래 링크를 확인하자.

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

 

10565번: Salary Inequity

There is a large company of N employees. With the exception of one employee, everyone has a direct supervisor. The employee with no direct supervisor is indirectly a supervisor of all other employees in the company. We say that employee X is a subordinate

www.acmicpc.net

루트가 있는 트리에서 각 노드의 서브트리에 대한 쿼리는 Euler Tour Technique을 이용해 노드의 인덱스를 새로 부여한 다음 배열의 구간쿼리로 바꿔 처리할 수 있음을 기억하자.

 

문제를 해결하기 위해 구현해야 할 쿼리는 구간의 각 원소의 값을 증가시키는 쿼리와 구간의 최솟값 및 최댓값을 구하는 쿼리이다. 이는 lazy propagation을 적용한 segment tree를 이용해 해낼 수 있다.

 

여러 테스트케이스를 처리해야하므로 전역변수를 사용할 경우 변수의 초기화에 유의하자.

 

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

#include <iostream>
#include <vector>
#include <cstring>
using namespace std;

int T, N, Q;
int idx[1000001];
int invidx[1000001];
int ccnt[1000001];
vector<int> G[1000001];

int dfi = 1;
int dfs(int cur) {
	int childcnt = 0;
	idx[cur] = dfi;
	invidx[dfi] = cur;
	dfi++;

	for (auto& nxt : G[cur]) {
		childcnt += dfs(nxt);
	}

	ccnt[idx[cur]] = childcnt;

	return childcnt + 1;
}

int arr[1000001];
pair<int, int> seg[2097153];
int lazy[2097153];

pair<int, int> init(int L, int R, int sI) {
	if (L < R) {
		pair<int, int> pL = init(L, (L + R) / 2, sI * 2), pR = init((L + R) / 2 + 1, R, sI * 2 + 1);
		return seg[sI] = make_pair(min(pL.first, pR.first), max(pL.second, pR.second));
	}
	return seg[sI] = make_pair(arr[invidx[L]], arr[invidx[L]]);
}

void prop(int L, int R, int sI) {
	seg[sI].first += lazy[sI], seg[sI].second += lazy[sI];
	if (L < R) lazy[sI * 2] += lazy[sI], lazy[sI * 2 + 1] += lazy[sI];
	lazy[sI] = 0;
}

pair<int, int> upd(int L, int R, int qL, int qR, int qVal, int sI) {
	if (lazy[sI]) prop(L, R, sI);
	if (R < qL || qR < L) return seg[sI];
	if (qL <= L && R <= qR) {
		lazy[sI] += qVal;
		prop(L, R, sI);
		return seg[sI];
	}
	pair<int, int> pL = upd(L, (L + R) / 2, qL, qR, qVal, sI * 2), pR = upd((L + R) / 2 + 1, R, qL, qR, qVal, sI * 2 + 1);
	return seg[sI] = make_pair(min(pL.first, pR.first), max(pL.second, pR.second));
}

pair<int, int> qry(int L, int R, int qL, int qR, int sI) {
	if (lazy[sI]) prop(L, R, sI);
	if (R < qL || qR < L) return make_pair(1000000007, -1000000007);
	if (qL <= L && R <= qR) return seg[sI];
	pair<int, int> pL = qry(L, (L + R) / 2, qL, qR, sI * 2), pR = qry((L + R) / 2 + 1, R, qL, qR, sI * 2 + 1);
	return make_pair(min(pL.first, pR.first), max(pL.second, pR.second));
}

void solve() {
	cin >> N;
	for (int i = 1; i <= N; i++) G[i].clear();
	dfi = 1;
	memset(lazy, 0, sizeof(lazy));
	for (int i = 2; i <= N; i++) {
		int x; cin >> x;
		G[x].emplace_back(i);
	}

	dfs(1);

	for (int i = 1; i <= N; i++) cin >> arr[i];

	init(1, N, 1);

	cin >> Q;
	while (Q--) {
		char q; cin >> q;
		if (q == 'R') {
			int qL, qVal; cin >> qL >> qVal;
			qL = idx[qL];
			upd(1, N, qL, qL + ccnt[qL], qVal, 1);
		}
		else {
			int qL; cin >> qL;
			qL = idx[qL];
			pair<int, int> pQ = qry(1, N, qL, qL + ccnt[qL], 1);
			cout << pQ.second - pQ.first << '\n';
		}
	}
}

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

	cin >> T;
	while (T--) solve();
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 21318 // C++] 피아노 체조  (0) 2024.02.03
[BOJ 16401 // C++] 과자 나눠주기  (0) 2024.02.02
[BOJ 1888 // C++] 곰팡이  (0) 2024.01.31
[BOJ 1388 // C++] 바닥 장식  (1) 2024.01.30
[BOJ 11123 // C++] 양 한마리... 양 두마리...  (1) 2024.01.29

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

 

이번에 볼 문제는 백준 1888번 문제인 곰팡이이다.
문제는 아래 링크를 확인하자.

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

 

1888번: 곰팡이

첫 줄에 곰팡이가 피어 있는 벽의 크기를 나타내는 두 정수 m과 n이 주어진다. (1 ≤ m, n ≤100) 둘째 줄부터는 벽의 상황이 한 줄에 한 행씩 주어진다. 곰팡이가 피어있는 곳은 그 곰팡이의 자라는

www.acmicpc.net

어느 순간에 모든 곰팡이가 한 덩어리가 되는지를 구하는 문제이다.

 

매 초마다 (1) 현재 모든 곰팡이가 연결되어있는지를 bfs를 통해 확인하고 (2) 그렇지 않다면 1초 뒤의 곰팡이의 상태를 나타내는 판을 새로 만드는 것을 반복해 문제를 해결하자.

 

초기상태로부터 길어야 100일 이내에 곰팡이는 한 덩어리가 되고, 각 곰팡이에 대해 번져나갈 칸을 하나하나 조사하는 것은 많아야 1만개의 칸에서 주변 121개의 칸을 조사하는 것으로 가능하므로 무식한 구현으로도 2초의 제한시간 내에 충분히 통과할 수 있다.

 

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

#include <iostream>
#include <utility>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;

int R, C, sR, sC;
char board[100][100];
char tmp[100][100];
int ans, cnt;
int visited[100][100];

int dr[4] = { 1,-1,0,0 };
int dc[4] = { 0,0,1,-1 };

queue<pair<int, int>> que;

int bfs() {
	int ret = 1;
	memset(visited, 0, sizeof(visited));

	que.push(make_pair(sR, sC));
	visited[sR][sC] = 1;
	while (!que.empty()) {
		int r = que.front().first, c = que.front().second; que.pop();
		for (int i = 0; i < 4; i++) {
			int rr = r + dr[i], cc = c + dc[i];
			if (rr < 0 || rr >= R || cc < 0 || cc >= C) continue;
			if (board[rr][cc] && !visited[rr][cc]) {
				visited[rr][cc] = 1;
				que.push(make_pair(rr, cc));
				ret++;
			}
		}
	}

	return ret;
}

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

	cin >> R >> C;
	for (int r = 0; r < R; r++) {
		for (int c = 0; c < C; c++) {
			cin >> board[r][c];
			if (board[r][c] > '0') {
				sR = r, sC = c;
				cnt++;
			}
			else board[r][c] = 0;
		}
	}

	if (!board[sR][sC]) {
		cout << 0;
		return 0;
	}

	while (bfs() < cnt) {
		ans++;
		for (int r = 0; r < R; r++) {
			for (int c = 0; c < C; c++) {
				if (board[r][c]) {
					int k = board[r][c] - '0';
					for (int rr = r - k; rr <= r + k; rr++) {
						for (int cc = c - k; cc <= c + k; cc++) {
							if (rr < 0 || rr >= R || cc < 0 || cc >= C) continue;
							tmp[rr][cc] = max(tmp[rr][cc], board[r][c]);
						}
					}
				}
			}
		}
		swap(board, tmp);

		cnt = 0;
		for (int r = 0; r < R; r++) {
			for (int c = 0; c < C; c++) {
				if (board[r][c]) cnt++;
			}
		}
	}

	cout << ans;
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 16401 // C++] 과자 나눠주기  (0) 2024.02.02
[BOJ 10565 // C++] Salary Inequity  (1) 2024.02.01
[BOJ 1388 // C++] 바닥 장식  (1) 2024.01.30
[BOJ 11123 // C++] 양 한마리... 양 두마리...  (1) 2024.01.29
[BOJ 2790 // C++] F7  (0) 2024.01.28

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

 

이번에 볼 문제는 백준 1388번 문제인 바닥 장식이다.
문제는 아래 링크를 확인하자.

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

 

1388번: 바닥 장식

형택이는 건축가이다. 지금 막 형택이는 형택이의 남자 친구 기훈이의 집을 막 완성시켰다. 형택이는 기훈이 방의 바닥 장식을 디자인했고, 이제 몇 개의 나무 판자가 필요한지 궁금해졌다. 나

www.acmicpc.net

전체 바닥을 행방향으로 읽어나가면서 - 조각의 개수를 세고 열방향으로 읽어나가면서 | 조각의 개수를 세는 것으로 문제를 해결하자.

 

조각의 개수는 각 방향으로 읽어나가면서 해당 방향으로의 조각이 끊어지는 순간을 세는 식으로 구할 수 있다.

 

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

#include <iostream>
#include <string>
using namespace std;

int R, C;
string board[50];
int ans;

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

	cin >> R >> C;
	for (int r = 0; r < R; r++) cin >> board[r];

	for (int r = 0; r < R; r++) {
		bool tgt = 0;
		for (int c = 0; c < C; c++) {
			if (board[r][c] == '-') tgt = 1;
			else {
				if (tgt) ans++, tgt = 0;
			}
		}
		if (tgt) ans++;
	}
	for (int c = 0; c < C; c++) {
		bool tgt = 0;
		for (int r = 0; r < R; r++) {
			if (board[r][c] == '|') tgt = 1;
			else {
				if (tgt) ans++, tgt = 0;
			}
		}
		if (tgt) ans++;
	}

	cout << ans;
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 10565 // C++] Salary Inequity  (1) 2024.02.01
[BOJ 1888 // C++] 곰팡이  (0) 2024.01.31
[BOJ 11123 // C++] 양 한마리... 양 두마리...  (1) 2024.01.29
[BOJ 2790 // C++] F7  (0) 2024.01.28
[BOJ 2784 // C++] 가로 세로 퍼즐  (1) 2024.01.27

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

 

이번에 볼 문제는 백준 11123번 문제인 양 한마리... 양 두마리...이다.
문제는 아래 링크를 확인하자.

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

 

11123번: 양 한마리... 양 두마리...

얼마전에 나는 불면증에 시달렸지... 천장이 뚫어져라 뜬 눈으로 밤을 지새우곤 했었지.  그러던 어느 날 내 친구 광민이에게 나의 불면증에 대해 말했더니 이렇게 말하더군. "양이라도 세봐!"  

www.acmicpc.net

주어진 격자판의 '#'을 노드로, 인접한 '#'끼리의 관계를 에지로 모델링한 그래프의 connected component의 개수를 세는 문제이다.

 

connected component의 개수는 dfs, bfs등의 그래프탐색이나 disjoint set 등을 이용해 셀 수 있다. 글쓴이는 bfs를 이용해 문제를 해결하였다.

 

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

#include <iostream>
#include <string>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;

int T;
int R, C;
string board[100];
int visited[100][100];

int dr[4] = { 1,-1,0,0 };
int dc[4] = { 0,0,1,-1 };

queue<pair<int, int>> que;

void bfs(int sR, int sC) {
	visited[sR][sC] = 1;
	que.push(make_pair(sR, sC));

	while (!que.empty()) {
		int r = que.front().first, c = que.front().second; que.pop();
		for (int i = 0; i < 4; i++) {
			int rr = r + dr[i], cc = c + dc[i];
			if (rr < 0 || rr >= R || cc < 0 || cc >= C) continue;
			if (board[rr][cc] == '#' && !visited[rr][cc]) {
				visited[rr][cc] = 1;
				que.push(make_pair(rr, cc));
			}
		}
	}
}

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

	cin >> T;
	while (T--) {
		int ans = 0;
		memset(visited, 0, sizeof(visited));
		cin >> R >> C;
		for (int r = 0; r < R; r++) cin >> board[r];

		for (int r = 0; r < R; r++) {
			for (int c = 0; c < C; c++) {
				if (board[r][c] == '#' && !visited[r][c]) {
					ans++;
					bfs(r, c);
				}
			}
		}

		cout << ans << '\n';
	}
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 1888 // C++] 곰팡이  (0) 2024.01.31
[BOJ 1388 // C++] 바닥 장식  (1) 2024.01.30
[BOJ 2790 // C++] F7  (0) 2024.01.28
[BOJ 2784 // C++] 가로 세로 퍼즐  (1) 2024.01.27
[BOJ 2980 // C++] 도로와 신호등  (1) 2024.01.26

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

 

이번에 볼 문제는 백준 2790번 문제인 F7이다.
문제는 아래 링크를 확인하자.

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

 

2790번: F7

권위를 자랑하는 레이싱 대회 F7이 열릴 예정이다. F7은 드라이버의 순위가 자주 바뀌기 때문에 사람들에게 인기가 아주 많다. 상근이는 F7 레이싱의 엄청난 팬이지만, 마지막 레이싱과 중간고사

www.acmicpc.net

어떤 드라이버가 우승하기 좋은 최적의 경우는 (1) 그 드라이버가 1등을 하고 (2) 남은 드라이버들의 현재 점수의 역순으로 2등부터 N등까지 하는 것이다. 이 상황이 왔을 때 해당 드라이버가 우승을 할 수 있는지를 판단해 문제를 해결하자. 다만 이를 단순히 구현하기에는 입력의 크기가 크므로 효율적인 방법을 생각해보자.

 

먼저 주어진 드라이버들의 점수를 오름차순으로 정렬하자. 이 때 어떤 드라이버가 우승할 수 있는지를 판단하려면 이 배열에서 그 드라이버는 N점을, 남은 드라이버들은 차례대로 점수를 N-1 ~ 1점씩 받은 경우만을 생각하면 된다. 각 드라이버가 받을 점수는 어떤 드라이버를 고르더라도 고른 드라이버의 왼쪽인지 오른쪽인지에 따라서만 달라짐을 관찰하자.

 

위의 관찰을 이용해, 각각의 드라이버를 골랐을 때 그 왼쪽의 드라이버들의 (마지막 경수 후의, 위에서같이 점수를 받은 다음의) 점수의 최댓값과 오른쪽의 드라이버들의 점수의 최댓값을 전처리하고 이를 이용해 해당 드라이버가 우승할 수 있는지를 판단해 문제를 해결하자. 이 전처리는 \(O(N)\)에 해낼 수 있다.

 

전체 문제 해결에 드는 시간복잡도는 배열의 정렬시간인 \(O(NlgN)\)이다.

 

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

#include <iostream>
#include <algorithm>
using namespace std;

int N;
int arr[300000];
int maxL[300000], maxR[300000];
int ans;

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

	cin >> N;
	for (int i = 0; i < N; i++) cin >> arr[i];
	sort(arr, arr + N);
	
	maxL[0] = arr[0] + N - 1;
	for (int i = 1; i < N; i++) maxL[i] = max(arr[i] + (N - 1) - i, maxL[i - 1]);
	
	maxR[N - 1] = arr[N - 1] + 1;
	for (int i = N - 2; i > -1; i--) maxR[i] = max(arr[i] + (N - i), maxR[i + 1]);

	if (arr[0] + N >= maxR[1]) ans++;
	for (int i = 1; i + 1 < N; i++) {
		if (maxL[i - 1] <= arr[i] + N && arr[i] + N >= maxR[i + 1]) ans++;
	}
	if (maxR[N - 2] < arr[N - 1] + N) ans++;

	cout << ans;
}
728x90

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

 

이번에 볼 문제는 백준 2784번 문제인 가로 세로 퍼즐이다.
문제는 아래 링크를 확인하자.

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

 

2784번: 가로 세로 퍼즐

6개 단어를 3*3 가로 세로 퍼즐에 놓을 수 없다면 0을 출력한다. 그렇지 않다면, 3개 줄에 퍼즐을 출력한다. 만약 가능한 답이 여러개라면 사전순으로 앞서는 것을 출력한다. 사전순으로 비교를 할

www.acmicpc.net

주어진 6개 단어를 모두 사용하여 가로 세로 퍼즐을 올바르게 채울 수 있는지 여부를 판단하는 문제이다.

 

글쓴이는 주어진 단어들의 각각의 순열에 대하여 첫 세 단어를 가로로 나열한 퍼즐과 나중 세 단어를 세로로 나열한 퍼즐을 만들어 둘이 같은 경우 중 사전순으로 가장 빠른 답안을 출력해 문제를 해결하였다.

 

모든 순열에 접근하는 것은 next_permutation을 이용해 간단하게 해낼 수 있다.

 

c++의 문자열은 사전순 비교 연산 '<'가 정의되어 있으므로 사전순 비교 또한 간단하게 구현할 수 있다.

 

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

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

int pmt[6] = { 0,1,2,3,4,5 };
string s[6];
char bd1[3][3], bd2[3][3];

string ans = "zzzzzzzzzzzz";

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

	for (int i = 0; i < 6; i++) cin >> s[i];

	while (1) {
		for (int r = 0; r < 3; r++) {
			for (int c = 0; c < 3; c++) bd1[r][c] = s[pmt[r]][c];
		}

		for (int c = 0; c < 3; c++) {
			for (int r = 0; r < 3; r++) bd2[r][c] = s[pmt[c + 3]][r];
		}

		bool sgn = 1;
		for (int r = 0; r < 3; r++) {
			for (int c = 0; c < 3; c++) {
				if (bd1[r][c] != bd2[r][c]) sgn = 0;
			}
		}

		if (sgn) ans = min(ans, s[pmt[0]] + s[pmt[1]] + s[pmt[2]]);

		if (!next_permutation(pmt, pmt + 6)) break;
	}

	if (ans.length() > 9) cout << 0;
	else cout << ans.substr(0, 3) << '\n' << ans.substr(3, 3) << '\n' << ans.substr(6, 3);
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 11123 // C++] 양 한마리... 양 두마리...  (1) 2024.01.29
[BOJ 2790 // C++] F7  (0) 2024.01.28
[BOJ 2980 // C++] 도로와 신호등  (1) 2024.01.26
[BOJ 4657 // C++] Image Perimeters  (0) 2024.01.25
[BOJ 8219 // C++] Coprime Numbers  (0) 2024.01.24

+ Recent posts