포스트

BOJ 24452 交易計画 (Trade Plan)

sorohue가 PS하는 블로그

BOJ 24452 交易計画 (Trade Plan)

문제 링크입니다.

문제 요약

그래프의 각 정점이 하나의 그룹에 속합니다. 이때, 두 정점 사이를 두 정점이 포함된 그룹의 정점들만 거쳐 오갈 수 있는지 구해야 합니다. 40만 번.

그룹 묶기

일단 같은 그룹이면서 서로 직접 연결되어 있는 정점들을 하나의 연결 요소로 묶습니다. 분리 집합을 이용합시다. 이를 이용해 두 그룹을 이어야 하는 경우를 처리합니다.

띠부띠부간선

주어진 쿼리를 그룹의 쌍에 따라 분류하면, 각 그룹의 쌍마다 두 그룹을 잇는 간선을 붙였다 뗐다 하면서 각 그룹의 쌍마다 답을 구할 수 있습니다. 각 간선이 최대 한 번 붙였다 뗐다 되게 됩니다. 분리 집합에서 경로 압축을 사용하지 않고, 최근 추가한 간선을 추가하지 않은 상태로 되돌리는 기능을 추가하면 이를 구현할 수 있습니다.

코드

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
56
57
58
59
60
61
62
63
64
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
using pll = pair<ll, ll>;

int par[404040], g[404040];
bool ans[404040];

stack<array<int,3>> st;
vector<pll> e, qry;

map<pll, vector<int>> Edge;
map<pll, vector<int>> Query;

int f(int x){
	return par[x] < 0 ? x : f(par[x]);
}

void u(int x, int y, bool flag = 1){
	x = f(x); y = f(y);
	if(x == y) return;
	if(par[x] > par[y]) swap(x, y);
	if(flag) st.push({x, y, par[y]});
	par[x] += par[y];
	par[y] = x;
}

void rollback(){
	while(st.size()){
		auto arr = st.top(); st.pop();
		par[arr[1]] = arr[2];
		par[arr[0]] -= arr[2];
	}
}

int main(){
	cin.tie(0); cout.tie(0); ios::sync_with_stdio(false);
	memset(par, -1, sizeof(par));
	int n, m, k; cin >> n >> m >> k;
	for(int i = 0; i < m; i++){
		int u, v; cin >> u >> v;
		e.push_back({u, v});
	}
	for(int i = 1; i <= n; i++) cin >> g[i];
	for(int i = 0; i < m; i++){
		if(g[e[i].first] == g[e[i].second]) u(e[i].first, e[i].second, 0);
		else if(g[e[i].first] > g[e[i].second]) Edge[{g[e[i].second], g[e[i].first]}].push_back(i);
		else Edge[{g[e[i].first], g[e[i].second]}].push_back(i);
	}
	int Q; cin >> Q;
	for(int i = 0; i < Q; i++){
		int a, b; cin >> a >> b;
		qry.push_back({a, b});
		if(g[a] == g[b]) ans[i] = (f(a) == f(b));
		else if(g[a] > g[b]) Query[{g[b], g[a]}].push_back(i);
		else Query[{g[a], g[b]}].push_back(i);
	}
	for(auto& [key, vec] : Query){
		for(auto& t : Edge[key]) u(e[t].first, e[t].second);
		for(auto& q : vec) ans[q] = (f(qry[q].first) == f(qry[q].second));
		rollback();
	}
	for(int i = 0; i < Q; i++) cout << ans[i] << '\n';
}
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.