Submission #198103

#TimeUsernameProblemLanguageResultExecution timeMemory
198103model_codeBuilding Skyscrapers (CEOI19_skyscrapers)C++17
100 / 100
2782 ms324140 KiB
/* Constructs the minimum required grid graph. Tracks connected components using union-find. Decides which cells may be deleted based on neighbourhoods, updates that information when necessary and keeps these cells in a set<>. O(N log N) */ #include <bits/stdc++.h> using namespace std; class HashPair { static inline size_t hash_combine(size_t h_first, size_t h_second) { return h_first ^ (h_second + 0x9e3779b9 + (h_first << 6) + (h_second >> 2)); } static inline size_t hash_int(unsigned int x) { x = ((x >> 16) ^ x) * 0x45d9f3b; x = ((x >> 16) ^ x) * 0x45d9f3b; x = (x >> 16) ^ x; return x; } public: size_t operator() (const pair<int, int> & p) const { size_t h_first = hash_int(p.first); size_t h_second = hash_int(p.second); return hash_combine(h_first, h_second); } }; class lego { int N, V; vector< pair<int, int> > cells, empty_cells; unordered_map< pair<int, int>, int, HashPair> cell_indices, empty_cell_indices; vector<char> removed; set<int> removable; vector<char> is_removable; vector< vector<int> > G4, G8; void construct_graphs(bool only_solvability = false) { constexpr static int dx[8] = {-1, -1, -1, 0, 1, 1, 1, 0}; constexpr static int dy[8] = { 1, 0, -1, -1, -1, 0, 1, 1}; if(!init_solvability_done) { for(int i = 0; i < N; i++) for(int j = 0; j < 8; j++) { pair<int, int> p = {cells[i].first + dx[j], cells[i].second + dy[j]}; auto it = cell_indices.find(p); int cell_id = (it == end(cell_indices)) ? -1 : it->second; if(cell_id == -1) { auto jt = empty_cell_indices.find(p); if(jt == end(empty_cell_indices)) { empty_cell_indices[p] = empty_cells.size(); cell_id = N + empty_cells.size(); empty_cells.push_back(p); G4.push_back({}); G8.push_back(vector<int>(8, cell_id)); } else cell_id = N + jt->second; G8[cell_id][4^j] = i; if(j % 2) G4[cell_id].push_back(i); } G8[i][j] = cell_id; if(j % 2) G4[i].push_back(cell_id); } } if(!init_done && !only_solvability) { for(int i = 0; i < (int)empty_cells.size(); i++) for(int j = 0; j < 8; j++) { if(G8[N+i][j] != N+i) continue; pair<int, int> p = {empty_cells[i].first + dx[j], empty_cells[i].second + dy[j]}; auto it = empty_cell_indices.find(p); if(it == end(empty_cell_indices)) continue; int cell_id = N + it->second; G8[N+i][j] = cell_id; if(j % 2) G4[N+i].push_back(cell_id); } } } int outer_component; vector< vector<int> > components4, components8; vector<int> comp4, comp8; vector<int> deg4, deg8; // degree = number of full neighbouring cells void find_components(bool only_solvability = false) { queue<int> q; if(!init_solvability_done) { components4.clear(); components4.resize(V); components8.clear(); components8.resize(V); comp4.clear(); comp4.resize(V, -1); comp8.clear(); comp8.resize(V, -1); deg4.clear(); deg4.resize(V, 0); deg8.clear(); deg8.resize(V, 0); for(int i = 0; i < V; i++) if(comp8[i] == -1 && !is_empty(i)) { comp8[i] = i; components8[i] = {i}; q.push(i); while(!q.empty()) { for(auto v : G8[q.front()]) if(comp8[v] == -1 && !is_empty(v)) { comp8[v] = i; components8[i].push_back(v); q.push(v); } q.pop(); } } } if(!init_done && !only_solvability) { for(int i = 0; i < V; i++) if(comp4[i] == -1 && is_empty(i)) { comp4[i] = i; components4[i] = {i}; q.push(i); while(!q.empty()) { for(auto v : G4[q.front()]) if(comp4[v] == -1 && is_empty(v)) { comp4[v] = i; components4[i].push_back(v); q.push(v); } q.pop(); } } for(int i = 0; i < V; i++) { for(auto v : G4[i]) if(!is_empty(v)) deg4[i]++; for(auto v : G8[i]) if(!is_empty(v)) deg8[i]++; } } } void add_edge(int v1, int v2) { int c1 = comp4[v1], c2 = comp4[v2]; if(c1 == c2) return; if(components4[c1].size() < components4[c2].size()) swap(c1, c2); for(auto v : components4[c2]) { comp4[v] = c1; components4[c1].push_back(v); } if(c2 == outer_component) outer_component = c1; for(auto v : components4[c2]) for(auto f : G8[v]) if(!is_empty(f)) update(f); } void update(int v) { static vector<char> seen = vector<char>(V, 0); bool reachable = false, articulation = false; for(auto adj : G4[v]) if(is_empty(adj)) if(comp4[adj] == outer_component) reachable = true; if(deg8[v] <= 1) { if(reachable) { if(!is_removable[v]) { removable.insert(v); is_removable[v] = 1; } } else if(is_removable[v]) { removable.erase(v); is_removable[v] = 0; } return; } for(int j = 0; j < 8; j++) if(is_empty(G8[v][j])) { if(is_empty(G8[v][(j+1)%8])) continue; // 1 cell per region if(j % 2 == 0 && !is_empty(G8[v][(j+7)%8])) continue; // ignore corner gaps int c = comp4[G8[v][j]]; if(seen[c]) { articulation = true; break; } seen[c]++; } for(int j = 0; j < 8; j++) if(is_empty(G8[v][j])) seen[comp4[G8[v][j]]] = 0; if(reachable && !articulation) { if(!is_removable[v]) { removable.insert(v); is_removable[v] = 1; } } else if(is_removable[v]) { removable.erase(v); is_removable[v] = 0; } } inline bool is_empty(int cell) { return (cell >= N || removed[cell]); } bool init_done, init_solvability_done; void init_solvability() { if(init_solvability_done) return; construct_graphs(true); V = G4.size(); removed.resize(V, false); find_components(true); init_solvability_done = true; } void init() { if(init_done) return; construct_graphs(); if(!init_solvability_done) { V = G4.size(); removed.resize(V, false); } find_components(); int min_coord = cells[0].first; for(int i = N; i < V; i++) if(min_coord >= empty_cells[i-N].first) { min_coord = empty_cells[i-N].first; outer_component = comp4[i]; } is_removable.resize(N, 0); for(int i = 0; i < N; i++) update(i); init_done = init_solvability_done = true; } public: lego(vector< pair<int, int> > cells_) : N(cells_.size()), cells(cells_) { for(int i = 0; i < N; i++) cell_indices[cells[i]] = i; G4.resize(N); G8.resize(N, vector<int>(8)); G4.reserve(9*N); G8.reserve(9*N); cell_indices.reserve(N); empty_cell_indices.reserve(8*N); init_done = init_solvability_done = false; } bool solvable() { init_solvability(); return ((int)components8[comp8[0]].size() == N); } int remove() { init(); if(removable.empty()) return -1; int rm_id = *rbegin(removable); removable.erase(--end(removable)); removed[rm_id] = true; components4[rm_id] = {rm_id}; comp4[rm_id] = rm_id; for(auto f : G4[rm_id]) if(!is_empty(f)) update(f); for(auto v : G4[rm_id]) { if(is_empty(v)) add_edge(rm_id, v); else deg4[v]--; } for(auto v : G8[rm_id]) { deg8[v]--; if(!is_empty(v)) update(v); } return rm_id; } }; int main() { cin.sync_with_stdio(0); cin.tie(0); int N, t; cin >> N >> t; vector< pair<int, int> > cells(N); for(int i = 0; i < N; i++) cin >> cells[i].first >> cells[i].second; lego solver(cells); if(!solver.solvable()) { cout << "NO\n"; return 0; } cout << "YES\n"; vector<int> build; for(int i = 0; i < N; i++) { int removed_cell_id = solver.remove(); assert(removed_cell_id != -1); build.push_back(removed_cell_id+1); } reverse(begin(build), end(build)); for(int i = 0; i < N; i++) cout << build[i] << "\n"; }
#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...