/**
* 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.
* [After contest] I realized that i forgot how to use a difference array on a tree.
* That's why i couldn't solve the last testcase. Noooo..
*
* PS1 I think this is the problem for which i wrote the most code.. In general, I
* think CEOI 2017 Day 1 is more technical, instead of requiring ingenius thoughts.
* PS2 It turns out that we don't even need to compute LCA. (+1/-1 cancels out)
*
* ------ 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 ------
* We have a tree in which a mouse runs. [S1] is just a brute-force.
*
* Time Complexity 1: O(n + m + p)
* Time Complexity 2: O(n * log(n * VAL_MAX) * log(n))
* Time Complexity 3: O()
* Implementation 1
*/
#include <bits/stdc++.h>
typedef int64_t int_t;
typedef std::vector<int_t> vec;
const int_t INF = 0x3f3f3f3f3f3f;
const int_t LCA_HEIGHT = 18;
inline int_t log2(int_t k) { return sizeof(int_t) * 8 - __builtin_clzll(k) - 1; }
// 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;
void dfs1(int_t k, int_t parent, const std::vector<adj_list_t>& graph,
std::vector<bool>& tree_edge, vec& depth, std::vector<bool>& visited) {
visited[k] = true;
if (parent != -1)
depth[k] = depth[parent] + 1;
else
depth[k] = 0;
for (const neighb_t& child : graph[k]) {
if (child.neighb == parent || visited[child.neighb])
continue;
tree_edge[child.edge_idx] = true;
dfs1(child.neighb, k, graph, tree_edge, depth, visited);
}
}
void dfs2(int_t k, int_t parent, const std::vector<adj_list_t>& graph,
const std::vector<bool>& tree_edge, vec& across, const vec& depth,
std::vector<bool>& is_bridge) {
across[k] = 0;
int_t backward_up = 0, backward_down = 0;
for (const neighb_t& child : graph[k]) {
if (tree_edge[child.edge_idx] && child.neighb != parent) {
dfs2(child.neighb, k, graph, tree_edge, across, depth, is_bridge);
across[k] += across[child.neighb];
} else {
if (depth[child.neighb] > depth[k])
backward_down++;
else if (depth[child.neighb] < depth[k])
backward_up++;
}
}
if (parent != -1) // the tree edge linking to parent
backward_up--;
across[k] += backward_up - backward_down;
assert(across[k] >= 0);
if (parent != -1 && across[k] == 0) {
for (const neighb_t& child : graph[k]) {
if (child.neighb == parent)
is_bridge[child.edge_idx] = true;
}
}
}
// Find bridges in the graph with a DFS tree
// I learnt this from a tutorial on codeforces (about DFS trees)
std::vector<bool> find_bridge(int_t n, int_t m,
const std::vector<edge_t>& original_graph) {
std::vector<adj_list_t> graph(n);
for (int_t k = 0; k < m; k++) {
int_t a = original_graph[k].a, b = original_graph[k].b;
graph[a].push_back(neighb_t{b, k});
graph[b].push_back(neighb_t{a, k});
}
vec depth(n), across(n);
std::vector<bool> tree_edge(m, false);
std::vector<bool> visited(n, false);
std::vector<bool> is_bridge(m, false);
for (int_t k = 0; k < n; k++) {
if (!visited[k]) {
dfs1(k, -1, graph, tree_edge, depth, visited);
dfs2(k, -1, graph, tree_edge, across, depth, is_bridge);
}
}
return is_bridge;
}
int_t dfs3(int_t k, int_t parent, const std::vector<adj_list_t>& graph,
std::vector<bool>& visited, const vec& diff, vec& start) {
visited[k] = true;
int_t sum = 0, up_edge = -1;
for (const neighb_t& neighb : graph[k]) {
if (neighb.neighb == parent) {
up_edge = neighb.edge_idx;
} else {
sum += dfs3(neighb.neighb, k, graph, visited, diff, start);
}
}
sum += diff[k];
if (sum > 0)
start[up_edge] = parent;
else if (sum < 0)
start[up_edge] = k;
return sum;
}
int main() {
std::ios_base::sync_with_stdio(false);
std::cin.tie(NULL);
int_t n, m;
std::cin >> n >> m;
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--;
}
std::vector<bool> is_bridge = find_bridge(n, m, original_graph);
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
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::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 diff(n, 0); // difference array on a tree
for (int_t k = 0; k < pairs; k++) {
int_t src, dst;
std::cin >> src >> dst;
src = map[src - 1], dst = map[dst - 1];
diff[src]--, diff[dst]++;
}
std::vector<bool> visited(n, false);
vec start(m, -1); // start[]: edge a -> b, start = a.
for (int_t k = 0; k < n; k++) {
if (!visited[k])
dfs3(k, -1, graph, visited, diff, start);
}
std::string ans(m, 'B');
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';
}
}
}
std::cout << ans << '\n';
}
# |
결과 |
실행 시간 |
메모리 |
Grader output |
1 |
Correct |
0 ms |
212 KB |
Output is correct |
2 |
Correct |
0 ms |
212 KB |
Output is correct |
3 |
Correct |
1 ms |
340 KB |
Output is correct |
4 |
Correct |
1 ms |
340 KB |
Output is correct |
5 |
Correct |
1 ms |
468 KB |
Output is correct |
6 |
Correct |
1 ms |
340 KB |
Output is correct |
7 |
Correct |
1 ms |
468 KB |
Output is correct |
8 |
Correct |
1 ms |
340 KB |
Output is correct |
9 |
Correct |
1 ms |
340 KB |
Output is correct |
10 |
Correct |
1 ms |
340 KB |
Output is correct |
# |
결과 |
실행 시간 |
메모리 |
Grader output |
1 |
Correct |
0 ms |
212 KB |
Output is correct |
2 |
Correct |
0 ms |
212 KB |
Output is correct |
3 |
Correct |
1 ms |
340 KB |
Output is correct |
4 |
Correct |
1 ms |
340 KB |
Output is correct |
5 |
Correct |
1 ms |
468 KB |
Output is correct |
6 |
Correct |
1 ms |
340 KB |
Output is correct |
7 |
Correct |
1 ms |
468 KB |
Output is correct |
8 |
Correct |
1 ms |
340 KB |
Output is correct |
9 |
Correct |
1 ms |
340 KB |
Output is correct |
10 |
Correct |
1 ms |
340 KB |
Output is correct |
11 |
Correct |
35 ms |
9976 KB |
Output is correct |
12 |
Correct |
38 ms |
11500 KB |
Output is correct |
13 |
Correct |
54 ms |
13248 KB |
Output is correct |
14 |
Correct |
65 ms |
14736 KB |
Output is correct |
15 |
Correct |
75 ms |
15244 KB |
Output is correct |
16 |
Correct |
89 ms |
13464 KB |
Output is correct |
17 |
Correct |
78 ms |
16388 KB |
Output is correct |
18 |
Correct |
98 ms |
13468 KB |
Output is correct |
19 |
Correct |
94 ms |
18400 KB |
Output is correct |
20 |
Correct |
56 ms |
10872 KB |
Output is correct |
21 |
Correct |
39 ms |
10316 KB |
Output is correct |
# |
결과 |
실행 시간 |
메모리 |
Grader output |
1 |
Correct |
0 ms |
212 KB |
Output is correct |
2 |
Correct |
0 ms |
212 KB |
Output is correct |
3 |
Correct |
1 ms |
340 KB |
Output is correct |
4 |
Correct |
1 ms |
340 KB |
Output is correct |
5 |
Correct |
1 ms |
468 KB |
Output is correct |
6 |
Correct |
1 ms |
340 KB |
Output is correct |
7 |
Correct |
1 ms |
468 KB |
Output is correct |
8 |
Correct |
1 ms |
340 KB |
Output is correct |
9 |
Correct |
1 ms |
340 KB |
Output is correct |
10 |
Correct |
1 ms |
340 KB |
Output is correct |
11 |
Correct |
35 ms |
9976 KB |
Output is correct |
12 |
Correct |
38 ms |
11500 KB |
Output is correct |
13 |
Correct |
54 ms |
13248 KB |
Output is correct |
14 |
Correct |
65 ms |
14736 KB |
Output is correct |
15 |
Correct |
75 ms |
15244 KB |
Output is correct |
16 |
Correct |
89 ms |
13464 KB |
Output is correct |
17 |
Correct |
78 ms |
16388 KB |
Output is correct |
18 |
Correct |
98 ms |
13468 KB |
Output is correct |
19 |
Correct |
94 ms |
18400 KB |
Output is correct |
20 |
Correct |
56 ms |
10872 KB |
Output is correct |
21 |
Correct |
39 ms |
10316 KB |
Output is correct |
22 |
Correct |
95 ms |
17328 KB |
Output is correct |
23 |
Correct |
111 ms |
15884 KB |
Output is correct |
24 |
Correct |
122 ms |
15784 KB |
Output is correct |
25 |
Correct |
127 ms |
24196 KB |
Output is correct |
26 |
Correct |
106 ms |
18044 KB |
Output is correct |
27 |
Correct |
98 ms |
15992 KB |
Output is correct |
28 |
Correct |
27 ms |
6716 KB |
Output is correct |
29 |
Correct |
58 ms |
12072 KB |
Output is correct |
30 |
Correct |
55 ms |
11948 KB |
Output is correct |
31 |
Correct |
59 ms |
12516 KB |
Output is correct |
32 |
Correct |
64 ms |
15764 KB |
Output is correct |