제출 #1143654

#제출 시각아이디문제언어결과실행 시간메모리
1143654RufatRoad Service 2 (JOI24_ho_t5)C++20
0 / 100
0 ms320 KiB
#include <bits/stdc++.h> using namespace std; // Disjoint Set Union (DSU) structure for union-find operations. struct DSU { vector<int> parent; vector<int> rank; DSU(int n) { parent.resize(n); rank.assign(n, 0); for(int i = 0; i < n; i++) parent[i] = i; } int find(int a) { if(parent[a] == a)return a; return parent[a] = find(parent[a]); } // merge returns true if a merge happened. bool merge(int a, int b) { a = find(a), b = find(b); if(a == b)return false; if(rank[a] < rank[b]) swap(a,b); parent[b] = a; if(rank[a] == rank[b]) rank[a]++; return true; } }; // Global variables for grid dimensions. int H, W, Q; // We will store the status of horizontal segments (A) and vertical segments (B). // A[i] is a string of length (W-1) for row i (0-indexed) – segment between (i,j) and (i,j+1) // B[i] is a string of length (W) for the vertical segments between row i and i+1. vector<string> A; // size H. vector<string> B; // size H-1. // Repair cost for each east-west road (each row), 0-indexed. vector<int> Ccost; // We number intersections as: index = i * W + j, with i in [0,H-1], j in [0,W-1]. int idx(int i, int j){ return i * W + j; } // --- MAIN --- int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); cin >> H >> W >> Q; A.resize(H); for (int i = 0; i < H; i++){ cin >> A[i]; } B.resize(H-1); for (int i = 0; i < H-1; i++){ cin >> B[i]; } Ccost.resize(H); for (int i = 0; i < H; i++){ cin >> Ccost[i]; } int nInter = H * W; // (1) Compute the base connectivity (the grid’s DSU) using originally passable roads. DSU baseDSU(nInter); // Horizontal edges (only if A[i][j]=='1') for (int i = 0; i < H; i++){ for (int j = 0; j < W-1; j++){ if(A[i][j]=='1'){ int u = idx(i,j), v = idx(i,j+1); baseDSU.merge(u,v); } } } // Vertical edges (only if B[i][j]=='1') for (int i = 0; i < H-1; i++){ for (int j = 0; j < W; j++){ if(B[i][j]=='1'){ int u = idx(i,j), v = idx(i+1,j); baseDSU.merge(u,v); } } } // Compute each intersection’s base component id. vector<int> comp(nInter); for (int i = 0; i < nInter; i++){ comp[i] = baseDSU.find(i); } // (2) For each row, record the (distinct) base component ids that appear. vector<vector<int>> rowComps(H); for (int i = 0; i < H; i++){ int prev = -1; for (int j = 0; j < W; j++){ int id = comp[idx(i,j)]; if(j == 0 || id != prev){ rowComps[i].push_back(id); prev = id; } } sort(rowComps[i].begin(), rowComps[i].end()); rowComps[i].erase(unique(rowComps[i].begin(), rowComps[i].end()), rowComps[i].end()); } // (3) For each base component id, record in which rows it appears. // Note: base component ids range up to nInter. vector<vector<int>> compRows(nInter); for (int i = 0; i < H; i++){ for (int cid : rowComps[i]){ compRows[cid].push_back(i); } } for (int i = 0; i < nInter; i++){ if(!compRows[i].empty()){ sort(compRows[i].begin(), compRows[i].end()); compRows[i].erase(unique(compRows[i].begin(), compRows[i].end()), compRows[i].end()); } } // (4) Answer queries. // For each query we: // – Read T required intersections. // – “Compress” them to their base component ids (i.e. reqComps). // – If there is only one base component then output 0. // – Otherwise, we “gather” candidate rows (i.e. rows that appear for at least one required base component) // and for each such row, compute the intersection with reqComps. // – Then (greedily) process candidate rows (viewed as “hyperedges”) in increasing order of repair cost; // if a candidate row connects two or more “groups” (of required base components) that are not yet merged, // we “take” that repair (add its cost once) and merge the groups. // – Finally, if all required base components are merged into one group, we output the total cost; otherwise –1. // // (We note that the general problem is NP–hard; many contestants use such a greedy–hyperedge–DSU approach for partial/full score.) for (int qi = 0; qi < Q; qi++){ int T; cin >> T; vector<pair<int,int>> reqPoints(T); for (int i = 0; i < T; i++){ int x, y; cin >> x >> y; reqPoints[i] = {x-1, y-1}; // convert to 0-indexed } // Build the set of required base components. vector<int> reqComps; { unordered_set<int> s; for (int i = 0; i < T; i++){ int r = reqPoints[i].first, c = reqPoints[i].second; int compId = comp[idx(r,c)]; s.insert(compId); } reqComps.assign(s.begin(), s.end()); } sort(reqComps.begin(), reqComps.end()); if(reqComps.size() == 1){ cout << 0 << "\n"; continue; } // Map each required base component id to a compressed index. unordered_map<int,int> compToIndex; for (int i = 0; i < (int)reqComps.size(); i++){ compToIndex[reqComps[i]] = i; } int k = reqComps.size(); // (a) Gather candidate rows. For each required base component, // add all rows (from compRows) in which it appears. unordered_set<int> candRowsSet; for (int compId : reqComps) { for (int r : compRows[compId]) { candRowsSet.insert(r); } } vector<int> candRows; candRows.assign(candRowsSet.begin(), candRowsSet.end()); // Sort candidate rows by repair cost (if equal, by row index) sort(candRows.begin(), candRows.end(), [&](int r1, int r2){ if(Ccost[r1] == Ccost[r2]) return r1 < r2; return Ccost[r1] < Ccost[r2]; }); // (b) For each candidate row, compute the intersection between rowComps[r] and reqComps. // We only need candidate rows that “cover” at least 2 required base components. struct Candidate { int row; int cost; vector<int> comps; // these will be the indices (0 to k-1) corresponding to reqComps }; vector<Candidate> candidates; for (int r : candRows){ vector<int> inter; int i = 0, j = 0; while(i < (int)rowComps[r].size() && j < (int)reqComps.size()){ if(rowComps[r][i] == reqComps[j]){ inter.push_back(compToIndex[rowComps[r][i]]); i++; j++; } else if(rowComps[r][i] < reqComps[j]){ i++; } else { j++; } } if(inter.size() >= 2){ Candidate cand; cand.row = r; cand.cost = Ccost[r]; sort(inter.begin(), inter.end()); inter.erase(unique(inter.begin(), inter.end()), inter.end()); cand.comps = move(inter); candidates.push_back(cand); } } // (c) Process the candidate rows (hyperedges) in increasing order of cost. sort(candidates.begin(), candidates.end(), [](const Candidate &a, const Candidate &b){ if(a.cost == b.cost) return a.row < b.row; return a.cost < b.cost; }); // DSU for the query (on the k required base components). DSU queryDSU(k); int usedCost = 0; for (auto &cand : candidates) { // Determine the DSU groups among the required components in this candidate row. unordered_set<int> groups; for (int compIdx : cand.comps) { groups.insert(queryDSU.find(compIdx)); } if(groups.size() <= 1) continue; // Use this candidate row (i.e. repair that row) to merge all groups. int rep = *groups.begin(); bool mergedSomething = false; for (int compIdx : cand.comps) { if(queryDSU.merge(rep, compIdx)){ mergedSomething = true; } } if(mergedSomething){ usedCost += cand.cost; } // Check if all required nodes are now connected. int root0 = queryDSU.find(0); bool allConnected = true; for (int i = 1; i < k; i++){ if(queryDSU.find(i) != root0) { allConnected = false; break; } } if(allConnected) break; } int root0 = queryDSU.find(0); bool allConnected = true; for (int i = 1; i < k; i++){ if(queryDSU.find(i) != root0) { allConnected = false; break; } } if(allConnected) cout << usedCost << "\n"; else cout << -1 << "\n"; } return 0; }
#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...