문제: icpc.me/10838
트리에서 세가지 쿼리를 처리하는 문제이다.
1번 쿼리나 3번 쿼리에서 물어보는 질의를 답하기 위해서는 a와 b의 lca를 필수적으로 구해야한다.
고정된 트리에서 LCA는 전처리를 거친후에 logN의 시간에 구할 수 있지만 2번 쿼리가 트리의 구조를 바꿔버리기 때문에 힘들어질 뿐더러
1번, 3번 쿼리를 처리하기 위해 LCA를 구했다고 하더라도 색칠을하거나 색의 개수를 세려면 log시간에 처리하긴 힘들어보인다.
하지만 문제를 잘 읽어보면 paint와 count 연산 시 a번 노드와 b번 노드 사이의 최단경로의 길이는 항상 1,000 이하이다. 라는 조건을 찾을 수 있다.
이를 이용하여 LCA나 쿼리를 O(1000)의 시간에 해결해주면 문제를 해결할 수 있다.
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | #include <cstdio> #include <algorithm> #include <set> using namespace std; int n, m, q, x, y, z, par[100010], lca[100010], paint[100010]; int getlca(int x, int y, int k) { if (x == y)return x; int cnt = 0; while (x&&cnt < 1000) { lca[x] = k; x = par[x]; cnt++; } cnt = 0; while (y&&cnt < 1000) { if (lca[y] == k) return y; y = par[y]; } return 0; } int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= m; i++) { scanf("%d%d%d", &q, &x, &y); if (q == 1) { scanf("%d", &z); int anc = getlca(x, y, i); while (x != anc) { paint[x] = z; x = par[x]; } while (y != anc) { paint[y] = z; y = par[y]; } } else if (q == 2) par[x] = y; else { set<int> st; int anc = getlca(x, y, i); while (x != anc) { st.insert(paint[x]); x = par[x]; } while (y != anc) { st.insert(paint[y]); y = par[y]; } printf("%d\n", st.size()); } } return 0; } | cs |
'알고리즘 관련 > BOJ' 카테고리의 다른 글
BOJ)12995 트리나라 (1) | 2017.06.08 |
---|---|
BOJ)1405 미친 로봇 (0) | 2017.06.07 |
BOJ)14590 KUBC League (Small) (0) | 2017.06.06 |
BOJ)13538 XOR 쿼리 (0) | 2017.06.05 |
BOJ)1322 X와K (0) | 2017.06.05 |