Submission #607173

#TimeUsernameProblemLanguageResultExecution timeMemory
607173jophyyjhOne-Way Streets (CEOI17_oneway)C++14
30 / 100
14 ms468 KiB
/** * Notes during contest. * * ------ A ------ * Looks like that it's about strongly-connected components, cycles or bridges. I * think we can detect all cycles and merge all those nodes into one. The resulting * graph would be a tree, so we can then use a difference array to find each edge's * direction. Note that any edge in a cycle is B, and any edge not in cycles is a * "bridge". * !IMPORTANT! (Reminded by tinjyu during contest) !IMPORTANT! * Graph may not be CONNECTED. * * ------ B ------ * We iterate through all cost k. We can take at most k bets. If we can guarantee * a profit of p, min(#A_is_the_outcome, #B_is_the_outcome) >= p + k. Binary search * is ok. * For each k, we wanna find the max achievable for * min(#A_is_outcome, #B_is_outcome) - k. * * ------ C ------ * * Time Complexity 1: O(m^2) * Time Complexity 2: O(n * log(n * VAL_MAX) * log(n)) * Time Complexity 3: O() * Implementation 0.5 (test if my solution is correct, not optimized, slow) */ #include <bits/stdc++.h> typedef int64_t int_t; typedef std::vector<int_t> vec; const int_t INF = 0x3f3f3f3f3f3f; // a DSU impl that allows assigning a value to each set struct DSU { vec set, rank; int_t components; DSU(int_t n) { set.resize(n); rank.resize(n); for (int_t k = 0; k < n; k++) set[k] = k, rank[k] = 1; components = n; } inline int_t find(int_t k) { if (set[k] == k) return k; return set[k] = find(set[k]); } bool merge(int_t a, int_t b) { // merge b into a (keep a's value) a = find(a), b = find(b); if (a == b) return false; if (rank[b] > rank[a]) std::swap(a, b); set[b] = a, rank[a] += rank[b], components--; return true; } }; struct edge_t { int_t a, b; }; struct neighb_t { int_t neighb, edge_idx; }; typedef std::vector<neighb_t> adj_list_t; int main() { std::ios_base::sync_with_stdio(false); std::cin.tie(NULL); int_t n, m; std::cin >> n >> m; if (n > 3000) { std::cout << "bye" << std::endl; return 0; } std::vector<edge_t> original_graph(m); for (int_t k = 0; k < m; k++) { std::cin >> original_graph[k].a >> original_graph[k].b; original_graph[k].a--, original_graph[k].b--; } // TODO: improve bridge finding std::vector<bool> is_bridge(m); // std::cerr << "[debug] is_bridge[]: "; for (int_t k = 0; k < m; k++) { DSU dsu(n); for (int_t i = 0; i < m; i++) { if (i == k) continue; dsu.merge(original_graph[i].a, original_graph[i].b); } int_t c = dsu.components; dsu.merge(original_graph[k].a, original_graph[k].b); assert(0 <= c - dsu.components && c - dsu.components <= 1); is_bridge[k] = (c != dsu.components); // std::cerr << is_bridge[k]; } // std::cerr << std::endl; DSU compress(n); // used to compress the nodes for (int_t k = 0; k < m; k++) { if (!is_bridge[k]) compress.merge(original_graph[k].a, original_graph[k].b); } vec map(n, -1); // mapping an original node into one in our new graph // std::cerr << "[debug] map[]: "; for (int_t k = 0, new_graph_top = 0; k < n; k++) { if (map[compress.find(k)] == -1) map[compress.find(k)] = new_graph_top++; map[k] = map[compress.find(k)]; // std::cerr << map[k] << ' '; } // std::cerr << std::endl; std::vector<adj_list_t> graph(compress.components); for (int_t k = 0; k < m; k++) { int_t a = map[original_graph[k].a], b = map[original_graph[k].b]; if (a != b) { graph[a].push_back(neighb_t{b, k}); graph[b].push_back(neighb_t{a, k}); } } n = compress.components; int_t pairs; std::cin >> pairs; vec start(m, -1); // for each edge, if it's a -> b, start[] = a. // std::cerr << "[debug] requirements:" << std::endl; for (int_t k = 0; k < pairs; k++) { int_t src, dst; std::cin >> src >> dst; src = map[src - 1], dst = map[dst - 1]; // std::cerr << src << ' ' << dst << std::endl; if (src == dst) continue; // TODO: improve BFS std::queue<int_t> bfs_queue; std::vector<int_t> edge_num(n, -1), prev(n, -1); edge_num[src] = INF; // doesn't exist. Anything not -1 would be good bfs_queue.emplace(src); while (!bfs_queue.empty()) { int_t t = bfs_queue.front(); bfs_queue.pop(); if (t == dst) break; for (const neighb_t& e : graph[t]) { if (edge_num[e.neighb] != -1) continue; edge_num[e.neighb] = e.edge_idx, prev[e.neighb] = t; bfs_queue.push(e.neighb); } } for (int_t pt = dst; pt != src; pt = prev[pt]) { assert(edge_num[pt] != -1); start[edge_num[pt]] = prev[pt]; } } std::string ans(m, '@'); for (int_t k = 0; k < m; k++) { if (is_bridge[k]) { if (start[k] != -1) { if (map[original_graph[k].a] == start[k]) ans[k] = 'R'; else ans[k] = 'L'; } else { ans[k] = 'B'; } } else { ans[k] = 'B'; } } std::cout << ans << '\n'; }
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...