Submission #38617

#TimeUsernameProblemLanguageResultExecution timeMemory
38617farmersricePipes (CEOI15_pipes)C++14
100 / 100
1222 ms15708 KiB
#include <bits/stdc++.h> //#include <ext/pb_ds/assoc_container.hpp> //#pragma GCC optimize ("O3") //#pragma GCC target ("sse4") #pragma GCC target ("avx,tune=native") //Use above if bruteforcing with lots of small operations. Or just use it anytime, there's no downside. AVX is better slightly /* TASK: hidden LANG: C++11 */ using namespace std; //using namespace __gnu_pbds; typedef long long ll; typedef pair<int, int> pair2; typedef pair<int, pair<int, int> > pair3; typedef pair<int, pair<int, pair<int, int> > > pair4; #define MAXN 100013 #define INF 1000000000000000000LL #define mp make_pair #define add push_back #define remove pop int n, m; vector<int> adj[MAXN]; vector<pair<int, int>> answer; int depth[MAXN], lowestAdjDepth[MAXN]; struct UnionFind { int * id; int * size; int count; UnionFind(int sz) { id = new int[sz]; size = new int[sz]; count = sz; for (int i = 0; i < sz; i++) { size[i] = 1; id[i] = i; } } UnionFind(){} bool sameset(int p, int q) { return find(p) == find(q); } int find(int p) { if (p != id[p]) { id[p] = find(id[p]); } return id[p]; } void merge(int p, int q) { int rootp = find(p); int rootq = find(q); if (rootp == rootq) return; if (size[rootp] < size[rootq]) { id[rootp] = rootq; size[rootq] += size[rootp]; } else { id[rootq] = rootp; size[rootp] += size[rootq]; } count--; } } uf[2]; //returns subtree size void solve(int current, int parent) { assert(depth[current] >= 1); lowestAdjDepth[current] = depth[current]; //cout << "solving " << current << " lad dis " << lowestAdjDepth[current] << endl; bool t = false; for (int next : adj[current]) { if (next == parent && !t) {t = true; continue;} if (depth[next] >= 1) { lowestAdjDepth[current] = min(lowestAdjDepth[current], depth[next]); } else { //unvisited, let's go visit! depth[next] = depth[current] + 1; solve(next, current); lowestAdjDepth[current] = min(lowestAdjDepth[current], lowestAdjDepth[next]); //cout << "current is " << current << " lad next is " << lowestAdjDepth[next] << " depth current is " << depth[current] << endl; if (lowestAdjDepth[next] > depth[current]) { //the next node is in a biconnected component unaffected by current node answer.add(mp(current, next)); } } } } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); cin >> n >> m; uf[0] = UnionFind(n); uf[1] = UnionFind(n); for (int i = 0; i < m; i++) { int a, b; cin >> a >> b; a--;b--; if (!uf[0].sameset(a, b)) { adj[a].add(b); adj[b].add(a); uf[0].merge(a, b); } else if (!uf[1].sameset(a, b)) { adj[a].add(b); adj[b].add(a); uf[1].merge(a, b); } } for (int i = 0; i < n; i++) { if (depth[i] == 0) { depth[i] = 1; solve(i, -1); } } for (auto t : answer) { cout << t.first + 1 << ' ' << t.second + 1<< endl; } }
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...