Skip to main content
  1. Posts/
  2. Algorithm/

BOJ 25567 줄 세우기

·332 words·2 mins
Jiho Kim
Author
Jiho Kim
달려 또 달려

📝 문제 정보
#

🧐 관찰 및 접근
#

  • 구간합?을 하려면 결국 완성된 배열이 있으면 좋을거같은데..
  • 근데 줄이 다를때만 합치니까, 결국 완성된 줄은 고정적으로 존재한다!
  • 오프라인으로 잘 돌면서 처리하면 되는거같다.
  • 줄의 맨앞과 맨뒤가 어딘지 잘 관리하고, 모든 줄이 합쳐지지는 않을 수 있으니 이를 주의하자.

💻 풀이
#

  • 코드 (C++):
void solve(){
    int N; cin >> N;
    int sz = 0;
    vector<vector<int>> lines;
    rep(i, 0, N){
        int cnt; cin >> cnt;
        vector<int> line(cnt);
        rep(j, 0, cnt) cin >> line[j];
        lines.push_back(line);
        sz += cnt;
    }

    vector<array<int, 3>> Queries; // {query, a, b}
    int Q; cin >> Q;
    rep(i, 0, Q){
        int op, a, b; cin >> op >> a >> b;
        Queries.push_back({op, a, b});
    }

    // lineId[x] = i : x번 사람이 i번째 줄에 속함
    vector<int> lineId(sz+1);
    rep(i, 0, N) for(auto x: lines[i]) lineId[x] = i;

    UnionFind UF(N), UFrev(N);
    vector<int> nxt(N, -1);
    for(auto [op, a, b]: Queries){
        if(op == 2) continue;
        int lineA = lineId[a];
        int lineB = lineId[b];
        if(UF.find(lineA) != UF.find(lineB)){
            // lineA 뒤에 lineB 붙이기
            int tailA = UFrev.find(lineA);
            int headB = UF.find(lineB);
            nxt[tailA] = headB;
            UF.merge(lineA, lineB);
            UFrev.merge(lineB, lineA);
        }
    }

    vector<int> mergedLineId(sz+1);
    vector<int> mergedLineIdx(sz+1);
    vector<vector<ll>> pfsum(N);

    rep(i, 0, N) if(UF.find(i) == i){
        vector<int> order;
        int cur = i;
        while(cur != -1){
            for(auto x: lines[cur]) order.push_back(x);
            cur = nxt[cur];
        }

        for(int j = 0; j < (int)order.size(); j++){
            mergedLineId[order[j]] = i;
            mergedLineIdx[order[j]] = j;
        }
        pfsum[i].resize(order.size()+1);
        rep(j, 0, order.size()) pfsum[i][j+1] = pfsum[i][j] + order[j];
    }

    // 쿼리 처리
    UnionFind UF2(N);
    for(auto [op, a, b]: Queries){
        int lineA = lineId[a];
        int lineB = lineId[b];
        if(op == 1){
            if(UF2.merge(lineA, lineB)) cout << "YES\n";
            else cout << "NO\n";
        }
        else{
            if(UF2.find(lineA) != UF2.find(lineB)){
                cout << "-1\n";
                continue;
            }
            int mergedLine = mergedLineId[a];
            int idxA = mergedLineIdx[a];
            int idxB = mergedLineIdx[b];
            if(idxA > idxB) swap(idxA, idxB);
            cout << pfsum[mergedLine][idxB+1] - pfsum[mergedLine][idxA] << "\n";
        }
    }
}
🔒

구현 코드 잠금

아래 쿠팡 링크를 방문하시면 코드가 공개됩니다.
광고 수익이 블로그 운영에 도움이 됩니다 🙏

🛒 쿠팡 방문하고 코드 보기

방문 후 잠금이 자동으로 해제됩니다