# Zerojudge b966: APCS第三題 線段覆蓋長度 > **Link:** [Zerojudge b966](https://zerojudge.tw/ShowProblem?problemid=b966) --- ## Description: 給定一維座標上一些線段,求這些線段所覆蓋的長度,注意,重疊的部分只能算一次。 例如給定 4 個線段:$(5, 6)、(1, 2)、(4, 8)、(7, 9)$,如下圖,線段覆蓋長度為 6 。 ![題目示意圖](https://i.imgur.com/o0xexNz.png) --- ## Input Format & Output Format | Input Format | Output Format | |:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:------------------------------------------------------------:| | 第一列是一個正整數 $N$ ,表示此測資有 $N$ 個線段。接著的 $N$ 列每一列是一個線段的開始端點座標整數值 $L$ 和結束端點座標整數值 $R$ ,開始端點座標值小於等於結束端點座標值,兩者之間以一個空格區隔。其中30%的測資滿足, $N < 100 , 0 ≤ L , R < 1000$ ,並且線段沒有重疊。其中70%的測資滿足, $N < 100 , 0 ≤ L , R < 1000$ ,並且線段可能重疊。其中100%的測資滿足, $N < 10000 , 0 ≤ L , R < 10000000$ ,並且線段可能重疊。 | 輸出其總覆蓋的長度。本題為嚴格比對,請務必按照說明進行輸出。 | | | | --- ## Sample Input & Output **Input:** 輸入範例一: 5 160 180 150 200 280 300 300 330 190 210 輸入範例二: 1 120 120 **Output:** 輸出範例一: 110 輸出範例二: 0 --- ## 解題歷程 **【解題想法】**:排序 **【Tag】**:排序(Sorting)、貪心(Greedy)、掃描線(Sweep Line) * {x, y}:每個線段的「起點」座標 x 和「終點」座標 y。 * 排序:x 由小到大排序,x 相同的話,y 由大到小排序。 * 變數 left:目前線段的「起點」座標。 * 變數 right:目前線段的「終點」座標。 作法1-Sweep Line : ```cpp= #include <bits/stdc++.h> using namespace std; #define AC ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0); #define pii pair<int,int> #define f first #define s second bool cmp(pii a,pii b) { if(a.f==b.f) return a.s>b.s; else return a.f<b.f; } int main() { AC int n,x,y; while(cin>>n) { vector<pii> v; for(int i=0;i<n;i++) { cin>>x>>y; v.push_back({x,y}); } sort(v.begin(),v.end(),cmp); int left=0,right=0,ans=0; for(int i=0;i<v.size();i++) { if(v[i].f>=left) { ans+=(right-left); left=v[i].f; right=v[i].s; }else if(v[i].s>left){ right=v[i].s; } } ans+=(right-left); cout<<ans<<'\n'; } return 0; } ``` 作法2-把線段的開始端點和結束端點視為獨立的evnet,記錄覆蓋的線段數 : ```cpp= #include <iostream> #include <algorithm> #include <vector> using namespace std; int main() { int N, L, R; cin >> N; vector<pair<int,int>> v; for (int i = 0; i < N; i++) { cin >> L >> R; //把線段的開始端點和結束端點視為獨立的evnet //在線段的開始端點L處,event +1 v.push_back({L, 1}); //在線段的結束端點R處,event -1 v.push_back({R, -1}); } sort(v.begin(), v.end()); //now指向目前檢視的event //event為該座標點i, 對應一個左閉由開區間[i, i+1), 共被幾段線段覆蓋 int now = 0, event = 0, ans = 0; for (int i = 0; i <= 1e7; i++) { while (now < (int)v.size() && v[now].first == i) { event += v[now].second; now++; } if (event > 0) { ans++; } } cout << ans << "\n"; return 0; } ```