제출 #1259083

#제출 시각아이디문제언어결과실행 시간메모리
1259083maxilOne-Way Streets (CEOI17_oneway)C++20
100 / 100
99 ms33608 KiB
#include <bits/stdc++.h> using namespace std; static const int MAXN = 200000 + 5; static const int LOG = 20; int n, m, p; int U[MAXN], V[MAXN]; vector<pair<int,int>> g[MAXN]; // undirected multigraph: (to, edge_id) // --- Tarjan bridges (on multigraph, handles parallel edges & self-loops) --- int timerDFS, tin[MAXN], low[MAXN]; bool isBridge[MAXN]; void dfs_bridge(int u, int pe) { tin[u] = low[u] = ++timerDFS; for (auto [v, id] : g[u]) { if (id == pe) continue; if (!tin[v]) { dfs_bridge(v, id); low[u] = min(low[u], low[v]); if (low[v] > tin[u]) isBridge[id] = true; } else { // back-edge / parallel edges (including self-loop) lower low[u] low[u] = min(low[u], tin[v]); } } } // --- Compress 2-edge-connected components (contract non-bridge edges) --- int compOf[MAXN], compCnt; vector<pair<int,int>> treeAdj[MAXN]; // on components: (neighbor_comp, edge_id) only for bridges void dfs_comp(int u, int cid) { compOf[u] = cid; for (auto [v, id] : g[u]) { if (compOf[v]) continue; if (isBridge[id]) continue; // do not cross bridges when forming component dfs_comp(v, cid); } } // --- LCA on the bridge-forest --- int up[MAXN][LOG], depthC[MAXN], parentC[MAXN], edgeUp[MAXN]; // edgeUp[child] = bridge edge id to parent void dfs_lca(int u, int p) { parentC[u] = p; for (int k = 1; k < LOG; ++k) up[u][k] = up[ up[u][k-1] ][k-1]; for (auto [v, eid] : treeAdj[u]) if (v != p) { depthC[v] = depthC[u] + 1; up[v][0] = u; edgeUp[v] = eid; // bridge edge id connecting v -> u dfs_lca(v, u); } } int LCA(int a, int b) { if (a == 0 || b == 0) return 0; if (depthC[a] < depthC[b]) swap(a, b); int d = depthC[a] - depthC[b]; for (int k = LOG-1; k >= 0; --k) if (d & (1<<k)) a = up[a][k]; if (a == b) return a; for (int k = LOG-1; k >= 0; --k) { if (up[a][k] != up[b][k]) { a = up[a][k]; b = up[b][k]; } } return up[a][0]; } // --- Difference arrays on the component-forest --- int needUp[MAXN], needDown[MAXN]; // per component void addPath(int a, int b) { if (a == b) return; // within same 2ECC ⇒ free (already B) int l = LCA(a, b); if (l == 0) return; // different connected components (shouldn't happen if input has solution) // a -> ... -> l (go up), and l -> ... -> b (go down) needUp[a]++; needUp[l]--; needDown[b]++; needDown[l]--; } char ans[MAXN]; // answer for each original edge id: 'B','L','R','?' // propagate needs and decide each bridge edge orientation void dfs_accumulate(int u, int p) { for (auto [v, eid] : treeAdj[u]) if (v != p) { dfs_accumulate(v, u); needUp[u] += needUp[v]; needDown[u] += needDown[v]; // Decide orientation for this bridge eid along edge (u <-> v) // Case 1: only needUp[v] > 0 -> flow v -> u (towards root) // Case 2: only needDown[v] > 0 -> flow u -> v (away from root) // Case 3: both zero -> unconstrained => 'B' // (Both positive cannot happen because a solution is guaranteed.) if (needUp[v] > 0 && needDown[v] == 0) { // orient comp v -> comp u int a = U[eid], b = V[eid]; int ca = compOf[a], cb = compOf[b]; // If original direction a->b corresponds to (v->u), print 'R', else 'L' if (ca == v && cb == u) ans[eid] = 'R'; else ans[eid] = 'L'; } else if (needDown[v] > 0 && needUp[v] == 0) { // orient comp u -> comp v int a = U[eid], b = V[eid]; int ca = compOf[a], cb = compOf[b]; if (ca == u && cb == v) ans[eid] = 'R'; else ans[eid] = 'L'; } else { // unconstrained if (ans[eid] == 0) ans[eid] = 'B'; } } } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); if (!(cin >> n >> m)) return 0; for (int i = 1; i <= m; ++i) { int a, b; cin >> a >> b; U[i] = a; V[i] = b; g[a].push_back({b, i}); g[b].push_back({a, i}); } // 1) Tarjan to find bridges (graph can be disconnected) for (int i = 1; i <= n; ++i) if (!tin[i]) dfs_bridge(i, -1); // 2) Compress 2-edge-connected components for (int i = 1; i <= n; ++i) if (!compOf[i]) dfs_comp(i, ++compCnt); // Initialize answers: non-bridge edges are inside cycles ⇒ 'B' for (int i = 1; i <= m; ++i) if (!isBridge[i]) ans[i] = 'B'; // 3) Build the bridge-forest over components, store edge id on the adjacency for (int i = 1; i <= m; ++i) if (isBridge[i]) { int ca = compOf[U[i]], cb = compOf[V[i]]; treeAdj[ca].push_back({cb, i}); treeAdj[cb].push_back({ca, i}); } // 4) LCA preprocess on each tree in the forest // up[*][*] already 0; set roots wherever parentC==0 for (int r = 1; r <= compCnt; ++r) { if (parentC[r] == 0) { up[r][0] = 0; depthC[r] = 0; edgeUp[r] = 0; dfs_lca(r, 0); } } // 5) Read reachability pairs and add path constraints on component-forest cin >> p; for (int i = 0; i < p; ++i) { int x, y; cin >> x >> y; int cx = compOf[x], cy = compOf[y]; if (cx == cy) continue; // already satisfied within 2ECC addPath(cx, cy); } // 6) Accumulate needs and determine each bridge orientation for (int r = 1; r <= compCnt; ++r) { if (parentC[r] == 0) dfs_accumulate(r, 0); } // Any remaining bridge without constraint => 'B' for (int i = 1; i <= m; ++i) if (isBridge[i] && ans[i] == 0) ans[i] = 'B'; // 7) Output the string for (int i = 1; i <= m; ++i) cout << ans[i]; cout << '\n'; return 0; }
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...