본문 바로가기
풀이

[백준] 2185 - 직사각형의 합집합 (c++)

by 땅왕 2024. 11. 19.

https://www.acmicpc.net/problem/2185

IOI 1998 > Day 2 4번

 

문제 요약

직사각형 여러개가 입력으로 주어진다. 직사각형의 합집합의 둘레를 구해라

 

풀이 (Nlog(max_coord))

  • 스위핑
  • 세그먼트 트리

세그먼트 트리를 안 쓰고 N*(max_coord) 풀이도 충분히 돌아간다. 하지만 연습삼아 세그트리를 써서 시간복잡도가 좋은 풀이를 내봤다.

 

x축 y축 나눠서 스위핑을 한다고 생각해보자 둘레가 갱신되는 건 길이에 변화가 생기는 순간이란 관찰을 할 수 있다. 구간안에 전체 길이를 세그로 구하면 길이가 달라질 때, 달라진 만큼 답에 더해주면 된다. 중복을 제외하고 길이를 구하는 테크닉은 이 블로그에 자세히 나와있다.

https://ps.mjstudio.net/0-1-segment-tree

 

0-1 Segment Tree

전체 구간에서 1이상인 구간의 개수를 빠르게 업데이트하고 세보자.

ps.mjstudio.net

 

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define mid (st+en>>1)
const int N =2e4+2;

int seg[4*N],cnt[4*N];
void update(int i,int st,int en,int l,int r,int a) {
    if(r<st||l>en)
        return;
    if(l<=st&&en<=r) 
        seg[i]+=a;
    else
        update(i*2,st,mid,l,r,a),update(i*2+1,mid+1,en,l,r,a);
    if(seg[i])
        cnt[i]=en-st+1;
    else if(st==en)
        cnt[i]=0;
    else
        cnt[i]=cnt[i*2]+cnt[i*2+1];
}

int main() {
    cin.tie(0)->sync_with_stdio(0);
    int n; cin>>n;
    vector<array<int,4>> v1,v2;
    for(int i=0,x1,y1,x2,y2;i<n;i++) 
        cin>>x1>>y1>>x2>>y2,
        v1.push_back({min(x1,x2),-1,y1,y2}),v1.push_back({max(x1,x2),1,y1,y2}),
        v2.push_back({min(y1,y2),-1,x1,x2}),v2.push_back({max(y1,y2),1,x1,x2});

    ll ans=0;
    auto f = [&](vector<array<int,4>> &v) {
        sort(v.begin(),v.end());
        int l=0;
        for(auto& [x,s,y1,y2]:v) {
            if(y1>y2)
                swap(y1,y2);
            y1+=N/2;y2+=N/2;
            update(1,1,N,y1,y2-1,-s);
            if(cnt[1]!=l)
                ans+=abs(cnt[1]-l);
            l=cnt[1];
        }
    };
    f(v1);
    fill(seg,seg+4*N,0); fill(cnt,cnt+4*N,0);
    f(v2);
    cout<< ans;
}

'풀이' 카테고리의 다른 글

[백준] 3267 - TWO (c++)  (2) 2024.11.20
[백준] 2317 - 결혼식 (c++)  (1) 2024.11.19
[백준] 1854 - K번째 최단경로 (c++)  (0) 2024.11.18
[백준] 3233 - BRODOVI (c++)  (1) 2024.10.31
[백준] 3392 - 화성 지도 (c++)  (3) 2024.10.30