티스토리 뷰
문제
알고리즘
HLD
풀이
트리 위에서 두 가지 쿼리를 진행해야 합니다. 첫 번째는 $i$번째 정점의 색을 바꾸는 것. 두 번째는 1번 정점에서부터 $v$정점까지 가는 경로 중 첫 번째로 만나는 검은 정점의 번호를 출력하는 것입니다.
트리에서는 문제를 풀기가 어려우므로 HLD를 이용해서 쭉 펴도록 합시다. 일자 상태로 만들었다면 세그먼트 트리의 사용이 가능해집니다. 세그먼트 트리에서 인덱스가 작을수록 트리 위에서는 루트에 가깝습니다. 이러한 이유 때문에 $query$함수에서 세그먼트 트리 쿼리를 처리할 때, 왼쪽에 검은 정점이 있다면 바로 리턴을 했습니다. 오른쪽에 있는 구간은 왼쪽보다 루트로부터 멀기 때문입니다(처음으로 만나는 검은 정점이 아님).
세그먼트 트리의 리프노드에는 흰 정점이라면 0을 검은 정점이라면 해당 번호를 적어놓고 풀었습니다.
코드
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < n; ++i)
#define REP(i, n) for (int i = 1; i <= n; ++i)
using namespace std;
#define left (i << 1)
#define right (i << 1 | 1)
int N, M, cnt;
vector<vector<int>> adj;
vector<int> p, idx, st, top, tree;
void dfs(int here) {
st[here] = 1;
for (auto& there : adj[here]) {
if (there ^ p[here]) {
p[there] = here;
dfs(there);
st[here] += st[there];
int& HE = adj[here][0];
if (HE == p[here] || st[there] > st[HE])
swap(HE, there);
}
}
}
void hld(int here) {
idx[here] = cnt++;
for (auto there : adj[here]) {
if (there ^ p[here]) {
top[there] = there == adj[here][0] ? top[here] : there;
hld(there);
}
}
}
void update(int i) {
tree[idx[i] + N] = tree[idx[i] + N] ? 0 : i + 1;
i = idx[i] + N;
for (i >>= 1; i; i >>= 1) {
tree[i] = tree[left] ? tree[left] : (tree[right] ? tree[right] : 0);
}
}
int query(int l, int r) {
int ret = 0;
l += N;
r += N;
for (; l <= r; l >>= 1, r >>= 1) {
if ((l & 1) && tree[l++]) {
return tree[l - 1];
}
if (!(r & 1) && tree[r--]) {
ret = tree[r + 1];
}
}
return ret;
}
int solve(int u, int v) {
int ret = -1;
while (top[u] ^ top[v]) {
if (st[top[u]] < st[top[v]])
swap(u, v);
int cand = query(idx[top[v]], idx[v]);
ret = cand ? cand : ret;
v = p[top[v]];
}
if (idx[u] < idx[v])
swap(u, v);
int cand = query(idx[v], idx[u]);
ret = cand ? cand : ret;
return ret;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in", "r", stdin);
freopen("out", "w", stdout);
#endif
cin.tie(NULL);
cout.tie(NULL);
ios::sync_with_stdio(false);
cin >> N;
adj.resize(N);
p = idx = top = st = vector<int>(N);
rep(i, N - 1) {
int u, v;
cin >> u >> v;
--u, --v;
adj[u].emplace_back(v);
adj[v].emplace_back(u);
}
dfs(0);
hld(0);
tree.resize(N << 1);
cin >> M;
while (M--) {
int a, b;
cin >> a >> b;
--b;
if (a == 1) {
update(b);
} else {
cout << solve(0, b) << '\n';
}
}
return 0;
}
'Algorithm' 카테고리의 다른 글
[백준 15685] 드래곤 커브 (0) | 2020.12.30 |
---|---|
[백준 15663] N과 M (9) (0) | 2020.12.30 |
[백준 17025] Icy Perimeter (0) | 2020.12.28 |
[백준 17024] Grass Planting (0) | 2020.12.27 |
[백준 17408] 수열과 쿼리 24 (0) | 2020.12.26 |
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- spring boot
- SCC
- 동적계획법
- bfs
- 스위핑
- Segment tree
- Suffix Array
- greedy
- 이분매칭
- 이분탐색
- implementation
- 세그먼트트리
- Oracle
- sorting
- knapsack
- dijkstra
- string
- spring
- hld
- union find
- 정렬
- 좌표압축
- sweeping
- 2-SAT
- Fenwick
- DP
- kmp
- 펜윅트리
- 트라이
- dfs
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
글 보관함