Submission #803762

#TimeUsernameProblemLanguageResultExecution timeMemory
803762ngraceSimurgh (IOI17_simurgh)C++14
100 / 100
188 ms11500 KiB
#include "simurgh.h" #include <bits/stdc++.h> using namespace std; #define ve vector #define ll long long #define ii pair<int, int> #define fi first #define se second int N; set<int> ans; struct DSU{ int par[500]; int si=0; DSU(int siz){ si=siz; reset(); } void reset(){ for(int i=0; i<si; i++) par[i]=i; } int root(int x) { return (x==par[x]) ? x : par[x]=root(par[x]); } void doUnion(int a, int b){ par[root(a)]=root(b); } }; int edgeInd[500][500]; DSU components(500); int cutTime=0; ve<bool> vis(500, false); ve<int> firstTime(500, -1); ve<int> lowTime(500, -1); bool cutEdge[500][500]; void cutDFS(int cur, int par){ vis[cur]=true; firstTime[cur] = lowTime[cur] = cutTime++; for(int i=0; i<N; i++){ if(edgeInd[cur][i]==-1 || i==par) continue; if(vis[i]) lowTime[cur] = min(lowTime[cur], firstTime[i]); else{ cutDFS(i, cur); lowTime[cur] = min(lowTime[cur], lowTime[i]); if(lowTime[i] > firstTime[cur]) { cutEdge[cur][i] = cutEdge[i][cur]=true; } } } } ve<ii> cutEdges; void findCutEdges(){ cutDFS(0, 0); for(int i=0; i<N; i++){ for(int j=i+1; j<N; j++){ if(edgeInd[i][j]==-1) continue; if(!cutEdge[i][j]){ components.doUnion(i, j); } else{ ans.insert(edgeInd[i][j]); cutEdges.push_back({i, j}); } } } } ve<ii> baseTree; bool treeVis[500]; void treeDFS(int x){ treeVis[x]=true; for(int i=0; i<N; i++){ if(edgeInd[x][i]==-1) continue; if(!treeVis[i]){ baseTree.push_back({x, i}); treeDFS(i); } } } ve<ve<int>> cycs; bool earEdgeUsed[500][500]; bool inEar[500]; int earVis[500]; int curEarVis=0; bool debug=false; bool earDFS(int x, int par){ if(inEar[x]){ cycs.back().push_back(x); return true; } if(earVis[x] == curEarVis) return false; earVis[x] = curEarVis; cycs.back().push_back(x); for(int i=0; i<N; i++){ if(edgeInd[x][i]==-1 || cutEdge[x][i] || i==par) continue; if(earDFS(i, x)) return true; } cycs.back().pop_back(); return false; } ve<ii> knownEdges; void ear(int start){ ve<int> nodes = {start}; cycs.clear(); while(nodes.size()>0){ int cur=nodes.back(); int next=-1; for(int i=0; i<N; i++){ if(edgeInd[cur][i]==-1 || cutEdge[cur][i] || earEdgeUsed[cur][i]) continue; next=i; break; } if(next==-1){ nodes.pop_back(); continue; } cycs.push_back({cur}); inEar[cur]=true; curEarVis++; earVis[cur]=curEarVis; earDFS(next, cur); for(int i=0; i<cycs.back().size()-1; i++){ int a=cycs.back()[i]; int b=cycs.back()[i+1]; inEar[a]=true; if(!inEar[b]) nodes.push_back(b); inEar[b]=true; earEdgeUsed[a][b] = earEdgeUsed[b][a] = true; } } ve<ve<int>> adj(N); ve<int> vis(N, -1); ve<int> par(N, -1); ve<bool> foundNode(N,false); for(int earInd=0; earInd<cycs.size(); earInd++){ int s = cycs[earInd][0], e=cycs[earInd].back(); bool skip=true; for(int i=0; i<cycs[earInd].size(); i++){ if(!foundNode[cycs[earInd][i]]) skip=false; foundNode[cycs[earInd][i]] = true; } if(skip) continue; //bfs to get from e to s on adj of prev edges: queue<ii> q; q.push({e, e}); while(q.size()>0){ ii cur=q.front(); q.pop(); if(vis[cur.fi]==earInd) continue; vis[cur.fi]=earInd; par[cur.fi] = cur.se; if(cur.fi==s) break; for(int i:adj[cur.fi]) q.push({i, cur.fi}); } ve<int> cyc; int cur=s; while(par[cur]!=cur){ cyc.push_back(par[cur]); cur=par[cur]; } reverse(cyc.begin(), cyc.end()); int cycRedundant = cyc.size(); for(int i=0; i<cycs[earInd].size(); i++){ cyc.push_back(cycs[earInd][i]); } if(false){ cout<<"Ear "<<earInd<<": "; for(int i:cycs[earInd]) cout<<i<<" "; cout<<endl; } if(false){ cout<<"Cycle (redundant: "<<cycRedundant<<"): "; for(int i:cyc) cout<<i<<" "; cout<<endl; } //Brute force on the cycle: //set up tree: ve<int> tree; ve<int> treeInd(N); DSU inTree(N); int missing = cyc.size()-2; for(int i=0; i<cyc.size()-1; i++){ int a=cyc[i], b=cyc[i+1]; inTree.doUnion(a, b); tree.push_back(edgeInd[a][b]); treeInd[i] = i; if(i==missing){ treeInd[i] = -1; tree.pop_back(); } } for(ii it:baseTree){ if(inTree.root(it.fi)!=inTree.root(it.se)){ tree.push_back(edgeInd[it.fi][it.se]); inTree.doUnion(it.fi, it.se); } } int ma=0; ve<int> cou(cyc.size()-1, -1); for(int i=0; i<cyc.size()-1; i++){ int a=cyc[i], b=cyc[i+1]; if(i!=missing){ int newa = cyc[missing], newb = cyc[missing+1]; tree[treeInd[i]] = edgeInd[newa][newb]; treeInd[missing] = treeInd[i]; treeInd[i] = -1; missing = i; } cou[i] = count_common_roads(tree); ma = max(ma, cou[i]); } for(int i=0; i<cyc.size()-1; i++){ int a=cyc[i], b=cyc[i+1]; if(i==cyc.size()-2) continue;//so get a tree if(cou[i]<ma){ int ind = edgeInd[a][b]; if(ans.find(ind)==ans.end()) ans.insert(ind); } knownEdges.push_back({a, b}); } for(int i=0; i<cycs[earInd].size()-1; i++){ int a=cycs[earInd][i], b=cycs[earInd][i+1]; adj[a].push_back(b); adj[b].push_back(a); } } } ve<ii> knownTree; int deg[500]; void calcDeg(int x){ DSU con(N); ve<int> tree; int sub = 0; for(int i=0; i<N; i++){ if(edgeInd[x][i]==-1) continue; tree.push_back(edgeInd[x][i]); if(ans.find(edgeInd[x][i]) != ans.end()) sub++; con.doUnion(x, i); } for(ii it:knownTree){ if(con.root(it.fi) == con.root(it.se)) continue; tree.push_back(edgeInd[it.fi][it.se]); if(ans.find(edgeInd[it.fi][it.se]) != ans.end()) sub++; con.doUnion(it.fi, it.se); } deg[x] = count_common_roads(tree) - sub; } void solve(){ //with degree one verts, binary search for leaf edge and then remove vert. stack<int> s; for(int i=0; i<N; i++){ if(deg[i]==1) s.push(i); } while(ans.size()<N-1){ int x = s.top(); s.pop(); if(deg[x]==0) continue; int l=0, r=N-1; while(l<r){ int m=(l+r)/2; DSU con(N); ve<int> tree; int sub = 0; for(int i=l; i<=m; i++){ if(edgeInd[x][i]==-1) continue; tree.push_back(edgeInd[x][i]); if(ans.find(edgeInd[x][i]) != ans.end()) sub++; con.doUnion(x, i); } for(ii it:knownTree){ if(con.root(it.fi) == con.root(it.se)) continue; tree.push_back(edgeInd[it.fi][it.se]); if(ans.find(edgeInd[it.fi][it.se]) != ans.end()) sub++; con.doUnion(it.fi, it.se); } assert(tree.size()==N-1); int count = count_common_roads(tree) - sub; if(count >0) r=m; else l=m+1; } ans.insert(edgeInd[l][x]); deg[x]--; deg[l]--; if(deg[l]==1) s.push(l); } } std::vector<int> find_roads(int n, std::vector<int> u, std::vector<int> v) { N = n; if(n==2){ ve<int> res = {0}; return res; } for(int i=0; i<500; i++){ for(int j=0; j<500; j++){ edgeInd[i][j]=-1; } } for(int i=0; i < u.size(); i++){ edgeInd[u[i]][v[i]] = i; edgeInd[v[i]][u[i]] = i; } findCutEdges(); treeDFS(0); set<int> foundComp; for(int i=0; i<N; i++){ if(foundComp.find(components.root(i))==foundComp.end()){ foundComp.insert(components.root(i)); ear(i); } } //now know state of all edges in knownEdges and cutEdges, which together form a tree. for(ii it:knownEdges) knownTree.push_back(it); for(ii it:cutEdges) knownTree.push_back(it); for(int i=0; i<N; i++) calcDeg(i); solve(); ve<int> res; for(int i:ans) res.push_back(i); return res; }

Compilation message (stderr)

simurgh.cpp: In function 'void ear(int)':
simurgh.cpp:131:17: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  131 |   for(int i=0; i<cycs.back().size()-1; i++){
      |                ~^~~~~~~~~~~~~~~~~~~~~
simurgh.cpp:145:26: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<std::vector<int> >::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  145 |  for(int earInd=0; earInd<cycs.size(); earInd++){
      |                    ~~~~~~^~~~~~~~~~~~
simurgh.cpp:149:17: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  149 |   for(int i=0; i<cycs[earInd].size(); i++){
      |                ~^~~~~~~~~~~~~~~~~~~~
simurgh.cpp:176:17: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  176 |   for(int i=0; i<cycs[earInd].size(); i++){
      |                ~^~~~~~~~~~~~~~~~~~~~
simurgh.cpp:198:17: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  198 |   for(int i=0; i<cyc.size()-1; i++){
      |                ~^~~~~~~~~~~~~
simurgh.cpp:216:17: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  216 |   for(int i=0; i<cyc.size()-1; i++){
      |                ~^~~~~~~~~~~~~
simurgh.cpp:217:8: warning: unused variable 'a' [-Wunused-variable]
  217 |    int a=cyc[i], b=cyc[i+1];
      |        ^
simurgh.cpp:217:18: warning: unused variable 'b' [-Wunused-variable]
  217 |    int a=cyc[i], b=cyc[i+1];
      |                  ^
simurgh.cpp:228:17: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  228 |   for(int i=0; i<cyc.size()-1; i++){
      |                ~^~~~~~~~~~~~~
simurgh.cpp:230:8: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  230 |    if(i==cyc.size()-2) continue;//so get a tree
      |       ~^~~~~~~~~~~~~~
simurgh.cpp:240:17: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  240 |   for(int i=0; i<cycs[earInd].size()-1; i++){
      |                ~^~~~~~~~~~~~~~~~~~~~~~
simurgh.cpp: In function 'void solve()':
simurgh.cpp:276:18: warning: comparison of integer expressions of different signedness: 'std::set<int>::size_type' {aka 'long unsigned int'} and 'int' [-Wsign-compare]
  276 |  while(ans.size()<N-1){
      |        ~~~~~~~~~~^~~~
In file included from /usr/include/c++/10/cassert:44,
                 from /usr/include/x86_64-linux-gnu/c++/10/bits/stdc++.h:33,
                 from simurgh.cpp:4:
simurgh.cpp:302:22: warning: comparison of integer expressions of different signedness: 'std::vector<int>::size_type' {aka 'long unsigned int'} and 'int' [-Wsign-compare]
  302 |    assert(tree.size()==N-1);
      |           ~~~~~~~~~~~^~~~~
simurgh.cpp: In function 'std::vector<int> find_roads(int, std::vector<int>, std::vector<int>)':
simurgh.cpp:329:17: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  329 |  for(int i=0; i < u.size(); i++){
      |               ~~^~~~~~~~~~
#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...