Submission #45292

#TimeUsernameProblemLanguageResultExecution timeMemory
45292bugmenot111One-Way Streets (CEOI17_oneway)C++17
0 / 100
76 ms75640 KiB
/* if an edge is not a bridge it can be oriented either way; the orientation of the bridges is uniquely determined; let's call the input pairs "required pairs"; for each bridge B: if there is no required pair with a node from the first component of the graph and the second component of the graph: B can be oriented either way otherwise: orient B the same way as the required pair from component A to component B obviously, there cannot be two required pairs with different orientations because there can be no solution! Algorithm: Build "bridge tree" T of G For every pair going from comp(u) to comp(v) in T: orient all edges from comp(u) to LCA(comp(u), comp(v)) upwards orient all edges from LCA(comp(u), comp(v)) to comp(v) downwards The loop can be optimized by using a version of the difference array on the tree. */ #include <cstdio> #include <vector> #include <utility> #include <algorithm> #include <numeric> #include <string> #include <cstring> #include <cstdlib> #include <functional> #include <queue> #define MAXN 100100 typedef std::vector< std::pair<int, int> > edge_list; typedef std::vector< std::vector<int> > graph; typedef std::vector< std::vector< std::pair<int, int> > > labeled_edge_graph; struct bridge_tree { static const int N = 100100; static const int M = 100100; std::vector<int> g[N];int U[M],V[M]; //edge list representation of the graph. bool isbridge[M]; // if i'th edge is a bridge edge or not int visited[N];int arr[N],T; //supporting arrays int cmpno = 1; std::queue<int> Q[N]; int adj(int u,int e){ return U[e]==u?V[e]:U[e]; } int dfs0(int u,int edge) //marks all the bridges { visited[u]=1; arr[u]=T++; int dbe = arr[u]; for(int i=0;i<(int)g[u].size();i++) { int e = g[u][i]; int w = adj(u,e); if(!visited[w]) dbe = std::min(dbe,dfs0(w,e)); else if(e!=edge) dbe = std::min(dbe,arr[w]); } if(dbe == arr[u] && edge!=-1) isbridge[edge]=true; return dbe; } void dfs1(int v) //Builds the tree with each edge a bridge from original graph { int currcmp = cmpno; // current component no. Q[currcmp].push(v); // A different queue for each component, coz during bfs we shall go to another component (step of dfs) and then come back to this one and continue our bfs visited[v]=currcmp; while(!Q[currcmp].empty()) //bfs. Exploring all nodes of this component { int u = Q[currcmp].front(); Q[currcmp].pop(); for(int i=0;i<(int)g[u].size();i++) { int e = g[u][i]; int w = adj(u,e); if(visited[w])continue; //if the edge under consideration is bridge and //other side is not yet explored, go there (step of dfs) if(isbridge[e]) { cmpno++; dfs1(w); } else //else continue with our bfs { Q[currcmp].push(w); visited[w]=currcmp; } } } } }; std::vector<int> label_vertices(const int n, const int m, const edge_list& el) { static struct bridge_tree bt; std::vector<int> ans(n); for(int i = 0; i < m; i++) bt.U[i] = el[i].first, bt.V[i] = el[i].second; for(int i = 0; i < m; i++) bt.g[bt.U[i]].push_back(i); for(int i = 0; i < m; i++) bt.g[bt.V[i]].push_back(i); for(int i = 0; i < m; i++) if(!bt.visited[i]) bt.dfs0(i, -1); std::memset(bt.visited, 0, sizeof(bt.visited)); for(int i = 0; i < n; i++) if(!bt.visited[i]) bt.dfs1(i); for(int i = 0; i < n; i++) ans[i] = bt.visited[i] - 1; return ans; } std::vector<std::pair<int, int>> tree[MAXN]; struct f2lk_dsu { int par[MAXN]; int rnk[MAXN]; int find(int x) { return par[x] == x ? x : par[x] = find(par[x]); } void unite(int x, int y) { x = find(x); y = find(y); if(x == y) return; if(rnk[x] > rnk[y]) par[y] = x; else if(rnk[x] < rnk[y]) par[x] = y; else if(rnk[x] == rnk[y]) rnk[par[y] = x]++; } f2lk_dsu() { std::iota(par, par + MAXN, 0); } }; void offline_lca_aux(std::vector<int>& lc, edge_list* qr, int u, int p = -1) { static f2lk_dsu d; static int ancestor[MAXN]; static bool black[MAXN]; if(black[u] == true) return; ancestor[u] = u; for(const auto& pa: tree[u]) { int v = pa.first; if(v == p) continue; offline_lca_aux(lc, qr, v, u); d.unite(u, v); ancestor[d.find(u)] = u; } black[u] = true; for(const auto& p: qr[u]) if(black[p.first]) lc[p.second] = ancestor[d.find(p.first)]; } std::vector<int> offline_lca(const int n, const edge_list& queries) { static edge_list qr[MAXN]; std::vector<int> lc(queries.size()); for(int i = 0; i < queries.size(); i++) { auto p = queries[i]; qr[p.first].push_back({p.second, i}); qr[p.second].push_back({p.first, i}); } for(int i = 0; i < n; i++) offline_lca_aux(lc, qr, i); return lc; } void dfs(int* up_edges, int* down_edges, std::string& ans, const std::vector<int>& lab, const edge_list& el, int v = 0, int p = -1) { static bool visited[MAXN]; if(visited[v]) return; visited[v] = true; for(const auto& c: tree[v]) if(c.first != p) dfs(up_edges, down_edges, ans, lab, el, c.first, v); for(const auto& c: tree[v]) if(c.first != p) up_edges[v] += up_edges[c.first], down_edges[v] += down_edges[c.first]; for(const auto& c: tree[v]) if(c.first == p) { if(up_edges[v] == 0 && down_edges[v] > 0) ans[c.second] = lab[el[c.second].first] == p ? 'R' : 'L'; if(up_edges[v] > 0 && down_edges[v] == 0) ans[c.second] = lab[el[c.second].first] == p ? 'L' : 'R'; } } std::string solve(const int n, const int m, const int p, const edge_list& el, const edge_list& pairs) { static int up_edges[MAXN]; static int down_edges[MAXN]; static std::string ans(m, 'B'); edge_list p2(pairs); auto lab = label_vertices(n, m, el); // build bridge-block tree int n2 = *std::max_element(lab.begin(), lab.end()); for(int i = 0; i < m; i++) { int x = lab[el[i].first]; int y = lab[el[i].second]; if(x != y) { tree[x].push_back({y, i}); tree[y].push_back({x, i}); } } for(auto& p: p2) p = {lab[p.first], lab[p.second]}; p2.erase(std::remove_if(p2.begin(), p2.end(), [](std::pair<int, int> p){return p.first == p.second;}), p2.end()); std::sort(p2.begin(), p2.end()); p2.erase(std::unique(p2.begin(), p2.end()), p2.end()); auto lc = offline_lca(n2, p2); for(int i = 0; i < p2.size(); i++) { int x = p2[i].first; int y = p2[i].second; int l = lc[i]; printf("%d\n", l); up_edges[x]++; up_edges[l]--; down_edges[y]++; down_edges[l]--; } for(int i = 0; i < n2; i++) dfs(up_edges, down_edges, ans, lab, el); return ans; } int main(void) { int n, m, p; scanf("%d%d", &n, &m); edge_list edges(m); for(int i = 0; i < m; i++) { int x; int y; scanf("%d%d", &x, &y); edges[i] = {x - 1, y - 1}; } scanf("%d", &p); edge_list pairs(p); for(int i = 0; i < p; i++) { int x; int y; scanf("%d%d", &x, &y); pairs[i] = {x - 1, y - 1}; } puts(solve(n, m, p, edges, pairs).c_str()); return 0; }

Compilation message (stderr)

oneway.cpp: In function 'std::vector<int> offline_lca(int, const edge_list&)':
oneway.cpp:143:19: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
  for(int i = 0; i < queries.size(); i++) {
                 ~~^~~~~~~~~~~~~~~~
oneway.cpp: In function 'std::__cxx11::string solve(int, int, int, const edge_list&, const edge_list&)':
oneway.cpp:186:19: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
  for(int i = 0; i < p2.size(); i++) {
                 ~~^~~~~~~~~~~
oneway.cpp: In function 'int main()':
oneway.cpp:201:7: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
  scanf("%d%d", &n, &m);
  ~~~~~^~~~~~~~~~~~~~~~
oneway.cpp:206:8: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
   scanf("%d%d", &x, &y);
   ~~~~~^~~~~~~~~~~~~~~~
oneway.cpp:209:7: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
  scanf("%d", &p);
  ~~~~~^~~~~~~~~~
oneway.cpp:214:8: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
   scanf("%d%d", &x, &y);
   ~~~~~^~~~~~~~~~~~~~~~
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...