์ธ๊ทธ๋จผํธ ํธ๋ฆฌ(Segment Tree)
๋ฐฐ์ด ๋ด ๋ฒ์ ๊ฐ์ ๊ตฌํ๊ฑฐ๋ ํน์ ๋ฒ์์ ๊ฐ๋ค์ ๋ณ๊ฒฝํ ๋ ๋น ๋ฅด๊ฒ ์ ๊ทผํ๊ธฐ ์ํด ์ฌ์ฉํ๋ค. ์ด๋ฆ ๊ทธ๋๋ก ๊ตฌ๊ฐ๋ค์ ๋ณด์กดํ๊ณ ์๋ ํธ๋ฆฌ์ด๋ค.
- ๋ฆฌํ ๋ ธ๋๋ ๋ฐฐ์ด์ ๊ทธ ์ ์์ฒด๋ฅผ ์๋ฏธํ๊ณ ๋ฆฌํ ๋ ธ๋ ์ธ ๋ ธ๋๋ค์ ์์ ๋ ธ๋๋ฅผ ๋ํํ๋ ๊ฐ์ด๋ค.
- ๋ฆฌํ ๋ ธ๋๋ฅผ ์ ์ธํ ๋ ธ๋๋ ๋น์์ ธ์๋๋ฐ, ์ธ๊ทธ๋จผํธ ํธ๋ฆฌ์ ๋ชฉ์ ์ ๋ฐ๋ผ ์ฑ์์ผํ๋ค.
๊ธฐ๋ณธ ์๋ฆฌ : ํฉ
https://www.acmicpc.net/blog/view/9
1) ์ด๊ธฐํ : ์ธ๊ทธ๋จผํธ ํธ๋ฆฌ ๋ง๋ค๊ธฐ
// a: ๋ฐฐ์ด a
// tree: ์ธ๊ทธ๋จผํธ ํธ๋ฆฌ
// node: ์ธ๊ทธ๋จผํธ ํธ๋ฆฌ ๋
ธ๋ ๋ฒํธ
// node๊ฐ ๋ด๋นํ๋ ํฉ์ ๋ฒ์๊ฐ start ~ end
long long init(vector<long long>& a, vector<long long>& tree, int node, int start, int end)
{
// ๋ฆฌํ ๋
ธ๋์ผ ๊ฒฝ์ฐ
if (start == end)
return tree[node] = a[start];
int mid = (start + end) / 2;
return tree[node] = init(a, tree, node * 2, start, mid) + init(a, tree, node * 2 + 1, mid + 1, end);
}
2) ์ฟผ๋ฆฌ : ๊ตฌ๊ฐ ๊ฒ์
// node๊ฐ ๋ด๋นํ๋ ๊ตฌ๊ฐ์ด start ~ end ์ด๊ณ , ๊ตฌํด์ผํ๋ ํฉ์ ๋ฒ์๋ left ~ right ์ด๋ค.
long long query(vector<long long>& tree, int node, int start, int end, int left, int right)
{
// 1. ์์ ๋
ธ๋ ๋ ๋ค ๋ฒ์ ๋ฐ์ผ ๊ฒฝ์ฐ
if (left > end || right < start)
return 0;
// 2. ์์ ๋
ธ๋ ๋ ๋ค ๋ฒ์ ์์ ์์ ๊ฒฝ์ฐ
if (left <= start && end <= right)
return tree[node];
// 3. ์์ ๋
ธ๋ ์ค ํ๋๋ง ๋ฒ์ ์์ ์์ ๊ฒฝ์ฐ
int mid = (start + end) / 2;
return query(tree, node * 2, start, mid, left, right) + query(tree, node * 2 + 1, mid + 1, end, left, right);
}
3) ์ ๋ณ๊ฒฝํ๊ธฐ
long long update(vector<long long>& tree, int node, int start, int end, int index, long long value)
{
// 1. start ~ end์ index๊ฐ ํฌํจ๋์ง ์๋ ๊ฒฝ์ฐ
if (index < start || index > end)
return tree[node];
// 2. start ~ end์ index๊ฐ ํฌํจ๋๋ ๊ฒฝ์ฐ ์ค ๋ฆฌํ ๋
ธ๋์ผ ๊ฒฝ์ฐ
if (start == end)
return tree[node] += value;
// 3. start ~ end์ index๊ฐ ํฌํจ๋๋ ๊ฒฝ์ฐ ์ค ๋ฆฌํ ๋
ธ๋๊ฐ ์๋ ๊ฒฝ์ฐ
int mid = (start + end) / 2;
return tree[node] = update(tree, node * 2, start, mid, index, value) + update(tree, node * 2 + 1, mid + 1, end, index, value);
}
๋ฌธ์ : ํฉ
https://www.acmicpc.net/problem/3653
#include <iostream>
#include <vector>
using namespace std;
#define SIZE 200000 // n+m
int n, m;
vector<int> tree, idx;
int init(int node, int start, int end, int left, int right)
{
if (left > end || right < start)
return 0;
if (start == end)
return tree[node] = 1;
int mid = (start + end) / 2;
return tree[node] = init(node * 2, start, mid, left, right) + init(node * 2 + 1, mid + 1, end, left, right);
}
int query(int node, int start, int end, int left, int right)
{
if (left > end || right < start)
return 0;
if (left <= start && end <= right)
return tree[node];
int mid = (start + end) / 2;
return query(node * 2, start, mid, left, right) + query(node * 2 + 1, mid + 1, end, left, right);
}
int update(int node, int start, int end, int index, int value)
{
if (index > end || index < start)
return tree[node];
if (start == end)
return tree[node] += value;
int mid = (start + end) / 2;
return tree[node] = update(node * 2, start, mid, index, value) + update(node * 2 + 1, mid + 1, end, index, value);
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
int t;
cin >> t;
while (t--) {
tree.clear();
tree.resize(4 * SIZE + 1);
idx.clear();
idx.resize(SIZE / 2 + 1);
cin >> n >> m;
for (int i = 1; i <= n; i++)
idx[i] = m + i;
init(1, 1, m + n, m + 1, m + n);
for (int i = 0; i < m; i++) {
int num;
cin >> num;
cout << query(1, 1, m + n, 1, idx[num] - 1) << " ";
update(1, 1, m + n, idx[num], -1); // ํด๋น ๋๋น๋๋ฅผ ๊บผ๋ด๊ณ ์
๋ฐ์ดํธ
idx[num] = m - i;
update(1, 1, m + n, idx[num], 1); // ํด๋น ๋๋น๋๋ฅผ ๋งจ ์์ ๋ฃ๊ณ ์
๋ฐ์ดํธ
}
cout << '\n';
}
}
๋ฌธ์ : ๊ณฑ
https://www.acmicpc.net/problem/5676
#include <iostream>
using namespace std;
int tree[400004], arr[100001];
int init(int node, int start, int end)
{
if (start == end)
return tree[node] = arr[start];
int mid = (start + end) / 2;
return tree[node] = init(node * 2, start, mid) * init(node * 2 + 1, mid + 1, end);
}
int query(int node, int start, int end, int left, int right)
{
if (left > end || right < start)
return 1;
if (left <= start && end <= right)
return tree[node];
int mid = (start + end) / 2;
return query(node * 2, start, mid, left, right) * query(node * 2 + 1, mid + 1, end, left, right);
}
int update(int node, int start, int end, int index, int diff)
{
if (index < start || index > end)
return tree[node];
if (start == end)
return tree[node] = diff;
int mid = (start + end) / 2;
return tree[node] = update(node * 2, start, mid, index, diff) * update(node * 2 + 1, mid + 1, end, index, diff);
}
int main()
{
cin.tie(NULL);
cout.tie(NULL);
ios::sync_with_stdio(false);
int N, K;
while (cin >> N >> K) {
for (int i = 1; i <= N; i++) {
cin >> arr[i];
if (arr[i] > 0)
arr[i] = 1;
else if (arr[i] < 0)
arr[i] = -1;
}
init(1, 1, N);
while (K--) {
char c;
int i, j;
cin >> c >> i >> j;
if (c == 'C') {
if (j > 0)
j = 1;
else if (j < 0)
j = -1;
update(1, 1, N, i, j);
arr[i] = j;
}
else if (c == 'P') {
int answer = query(1, 1, N, i, j);
if (answer == 0)
cout << 0;
else if (answer > 0)
cout << '+';
else
cout << '-';
}
}
cout << '\n';
}
}
๋ฌธ์ : ์ต์๊ฐ
https://www.acmicpc.net/problem/2336
#include <iostream>
#include <algorithm>
using namespace std;
int scores[3][500001], tree[500001 * 4];
pair<int, int> firstTest[500001];
int query(int node, int start, int end, int left, int right)
{
if (left > end || right < start)
return 1e9;
if (left <= start && end <= right)
return tree[node];
int mid = (start + end) / 2;
return min(query(node * 2, start, mid, left, right), query(node * 2 + 1, mid + 1, end, left, right));
}
int update(int node, int start, int end, int index, int value)
{
if (index < start || index > end)
return tree[node];
if (start == end)
return tree[node] = value;
int mid = (start + end) / 2;
return tree[node] = min(update(node * 2, start, mid, index, value), update(node * 2 + 1, mid + 1, end, index, value));
}
int main()
{
cin.tie(NULL);
cout.tie(NULL);
ios::sync_with_stdio(false);
int n;
cin >> n;
for (int i = 0; i < 3; i++) {
for (int j = 1; j <= n; j++) {
int num;
cin >> num;
scores[i][num] = j;
}
}
for (int i = 1; i <= n * 4; i++)
tree[i] = 1e9;
// ์ฒซ๋ฒ์งธ ์ํ ๋ฑ์๋๋ก ์ ๋ ฌ
for (int i = 1; i <= n; i++)
firstTest[i] = { scores[0][i], i };
sort(firstTest + 1, firstTest + n + 1);
int ans = 0;
for (int i = 1; i <= n; i++) {
int index = firstTest[i].second;
// ์ต์๊ฐ์ด ํ์ฌ ์
๋ฐ์ดํธ ์ค์ธ ํ์์ ์ธ๋ฒ์งธ ์ํ ๋ฑ์๋ณด๋ค ํฌ๋ค๋ฉด ๊ต์ฅํ ํ์์ด๋ค.
if (query(1, 1, n, 1, scores[1][index]) > scores[2][index])
ans++;
update(1, 1, n, scores[1][index], scores[2][index]);
}
cout << ans;
}
๋ฌธ์ : ๋ ์ด์ง ํ๋กํผ๊ฒ์ด์ (Lazy Propagation)
https://www.acmicpc.net/problem/10999
#include <iostream>
#include <algorithm>
using namespace std;
const int SIZE = 1 << 21;
struct SegTree {
int treeStart;
long long tree[SIZE], lazy[SIZE];
SegTree()
{
treeStart = SIZE / 2;
fill(tree, tree + SIZE, 0);
fill(lazy, lazy + SIZE, 0);
}
void init()
{
for (int i = treeStart - 1; i > 0; i--)
tree[i] = tree[i * 2] + tree[i * 2 + 1];
}
// ๊ตฌ๊ฐ([start, end)) node์ lazy ๊ฐ์ propagate
void propagate(int node, int start, int end)
{
if (lazy[node] != 0) {
// ๋ฆฌํ ๋
ธ๋๊ฐ ์๋๋ฉด ์์๋ค์๊ฒ lazy ๋ฏธ๋ฃธ
if (node < treeStart) {
lazy[node * 2] += lazy[node];
lazy[node * 2 + 1] += lazy[node];
}
tree[node] += lazy[node] * (end - start);
lazy[node] = 0;
}
}
// ๊ตฌ๊ฐ([left, right))์ value๋ฅผ ๋ํ๋ผ
void update(int node, int start, int end, int left, int right, int value)
{
propagate(node, start, end);
if (left >= end || right <= start)
return;
if (left <= start && end <= right) {
lazy[node] += value;
propagate(node, start, end);
return;
}
int mid = (start + end) / 2;
update(node * 2, start, mid, left, right, value);
update(node * 2 + 1, mid, end, left, right, value);
tree[node] = tree[node * 2] + tree[node * 2 + 1];
}
// ๊ตฌ๊ฐ([left, right))์ ํฉ์ ๊ตฌํ๋ผ
long long sum(int node, int start, int end, int left, int right)
{
propagate(node, start, end);
if (left >= end || right <= start)
return 0;
if (left <= start && end <= right)
return tree[node];
int mid = (start + end) / 2;
return sum(node * 2, start, mid, left, right) + sum(node * 2 + 1, mid, end, left, right);
}
} seg;
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
int N, M, K;
cin >> N >> M >> K;
for (int i = 0; i < N; i++)
cin >> seg.tree[seg.treeStart + i];
seg.init();
for (int i = 0, a, b, c, d; i < M + K; i++) {
cin >> a;
if (a == 1) {
cin >> b >> c >> d;
seg.update(1, 0, seg.treeStart, b - 1, c, d);
}
else {
cin >> b >> c;
cout << seg.sum(1, 0, seg.treeStart, b - 1, c) << '\n';
}
}
}
๋ฌธ์ : ๋จธ์ง ์ํธ ํธ๋ฆฌ
https://www.acmicpc.net/problem/13544
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int SIZE = 1 << 18;
struct MergeSortTree {
vector<int> arr[SIZE];
void construct()
{
for (int i = SIZE / 2 - 1; i > 0; --i) {
vector<int>& c = arr[i], & l = arr[i * 2], & r = arr[i * 2 + 1];
arr[i].resize(l.size() + r.size());
for (int j = 0, p = 0, q = 0; j < c.size(); ++j)
c[j] = (q == r.size() || (p < l.size() && l[p] < r[q])) ? l[p++] : r[q++];
}
}
int greater(int left, int right, int value, int node = 1, int start = 0, int end = SIZE / 2)
{
if (end <= left || right <= start)
return 0;
if (left <= start && end <= right)
return arr[node].end() - upper_bound(arr[node].begin(), arr[node].end(), value); // value ๋ณด๋ค ํฐ ๊ฐ์
int mid = (start + end) / 2;
return greater(left, right, value, node * 2, start, mid) + greater(left, right, value, node * 2 + 1, mid, end);
}
}mst;
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
int N;
cin >> N;
for (int i = 0; i < N; ++i) {
int a;
cin >> a;
mst.arr[SIZE / 2 + i].push_back(a);
}
mst.construct();
int M, L = 0;
cin >> M;
while (M--) {
int i, j, k;
cin >> i >> j >> k;
L = mst.greater((i ^ L) - 1, j ^ L, k ^ L);
cout << L << '\n';
}
}