제출 #1302750

#제출 시각아이디문제언어결과실행 시간메모리
1302750vukhacminh도로 건설 사업 (JOI13_construction)C++20
0 / 100
38 ms3564 KiB
#include <bits/stdc++.h>
using namespace std;
using ll = long long;

struct Edge {
    int u, v;
    ll w;
    bool operator<(Edge const& other) const {
        return w < other.w;
    }
};

struct DSU {
    int n;
    vector<int> p, r;
    DSU(int n=0){ init(n); }
    void init(int n0){
        n = n0;
        p.resize(n);
        r.assign(n,0);
        for(int i=0;i<n;i++) p[i]=i;
    }
    int find(int x){ return p[x]==x?x:p[x]=find(p[x]); }
    bool unite(int a,int b){
        a = find(a); b = find(b);
        if(a==b) return false;
        if(r[a]<r[b]) swap(a,b);
        p[b]=a;
        if(r[a]==r[b]) r[a]++;
        return true;
    }
};

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int N, M, C;
    if(!(cin >> N >> M >> C)) return 0;
    vector<ll> X(N), Y(N);
    for(int i=0;i<N;i++) cin >> X[i] >> Y[i];
    struct Rect { ll P,Q,R,S; };
    vector<Rect> rects(M);
    for(int i=0;i<M;i++){
        cin >> rects[i].P >> rects[i].Q >> rects[i].R >> rects[i].S;
    }
    vector<pair<ll,int>> companies(C);
    for(int i=0;i<C;i++){
        ll B; int H;
        cin >> B >> H;
        companies[i] = {B, H};
    }

    // Tạo các cạnh: chỉ cho các cặp cùng x hoặc cùng y, kiểm tra xem đoạn thẳng có trùng hoặc chạm rect nào không.
    vector<Edge> edges;
    edges.reserve( (size_t)N * N / 4 );

    // Nhóm theo X để sinh các cặp cùng X
    unordered_map<ll, vector<int>> gx;
    gx.reserve(N*2);
    for(int i=0;i<N;i++) gx[X[i]].push_back(i);
    for(auto &kv : gx){
        auto &vec = kv.second;
        int k = (int)vec.size();
        // nếu muốn tối ưu, chỉ nối cặp k*(k-1)/2
        for(int i=0;i<k;i++){
            for(int j=i+1;j<k;j++){
                int a = vec[i], b = vec[j];
                ll x = X[a];
                ll y1 = Y[a], y2 = Y[b];
                ll lo = min(y1,y2), hi = max(y1,y2);
                bool ok = true;
                for(int t=0;t<M;t++){
                    ll P = rects[t].P, Q = rects[t].Q, R = rects[t].R, S = rects[t].S;
                    // đoạn đứng ở x; nếu x in [P,R] và y-interval giao với [Q,S] (kể cả chỉ chạm)
                    if(x >= P && x <= R){
                        ll inter_lo = max(lo, Q);
                        ll inter_hi = min(hi, S);
                        if(inter_lo <= inter_hi){
                            ok = false; break;
                        }
                    }
                }
                if(ok){
                    edges.push_back({a,b, llabs(y1-y2)});
                }
            }
        }
    }

    // Nhóm theo Y để sinh các cặp cùng Y
    unordered_map<ll, vector<int>> gy;
    gy.reserve(N*2);
    for(int i=0;i<N;i++) gy[Y[i]].push_back(i);
    for(auto &kv : gy){
        auto &vec = kv.second;
        int k = (int)vec.size();
        for(int i=0;i<k;i++){
            for(int j=i+1;j<k;j++){
                int a = vec[i], b = vec[j];
                ll y = Y[a];
                ll x1 = X[a], x2 = X[b];
                ll lo = min(x1,x2), hi = max(x1,x2);
                bool ok = true;
                for(int t=0;t<M;t++){
                    ll P = rects[t].P, Q = rects[t].Q, R = rects[t].R, S = rects[t].S;
                    // đoạn ngang ở y; nếu y in [Q,S] và x-interval giao với [P,R]
                    if(y >= Q && y <= S){
                        ll inter_lo = max(lo, P);
                        ll inter_hi = min(hi, R);
                        if(inter_lo <= inter_hi){
                            ok = false; break;
                        }
                    }
                }
                if(ok){
                    edges.push_back({a,b, llabs(x1-x2)});
                }
            }
        }
    }

    // Sắp cạnh theo trọng số tăng dần
    sort(edges.begin(), edges.end());

    // Tính comp_all = số thành phần khi dùng tất cả các cạnh hợp lệ
    DSU dsu_all(N);
    int comp_all = N;
    for(auto &e : edges){
        if(dsu_all.unite(e.u, e.v)) comp_all--;
    }

    // Với mỗi công ty xử lý Kruskal có điều kiện
    // (vì C <= 100 nên chạy lại Kruskal cho từng công ty là được)
    for(int idx=0; idx<C; idx++){
        ll B = companies[idx].first;
        int H = companies[idx].second;
        if(H < comp_all){
            cout << -1 << '\n';
            continue;
        }
        DSU dsu(N);
        int comps = N;
        long long sumEdges = 0;
        for(auto &e : edges){
            int u = e.u, v = e.v;
            ll w = e.w;
            if(dsu.find(u) == dsu.find(v)) continue;
            if(w < B || comps > H){
                // nối
                dsu.unite(u,v);
                sumEdges += w;
                comps--;
                if(comps == H && w >= B){
                    // we have reached required components; but still need to continue
                    // NOTE: if further edges with w < B exist they should still be added because they reduce cost.
                    // However since edges are sorted by w ascending, any later w will be >= current w.
                    // So to implement correctly we don't early break here; keep processing so that edges with w < B (smaller) are already processed earlier.
                }
            } else {
                // w >= B and comps <= H -> không cần nối, vì thêm cạnh này không giảm chi phí (w >= B)
                // và không bắt buộc (đã <= H)
                // do các cạnh sau có w tăng dần, không có gì cần làm
                // nhưng vẫn tiếp tục vì có thể có cạnh sau có w < B (không thể do sắp tăng dần)
            }
        }
        if(comps > H){
            // cố gắng nối nhưng không đủ cạnh để giảm xuống H
            cout << -1 << '\n';
        } else {
            long long total = sumEdges + (long long)comps * B;
            cout << total << '\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...