codeforces 1285E. Delete a Segment


鏈接:https://codeforces.com/problemset/problem/1285/E

題意:給一個數軸上有n個線段集,線段集若有相交,則合並為一個新的合並線段集,比如[1,6]和[2,9],因為兩個線段有相交,所以要合並為[1,9],先問刪掉給定的n個線段集中的任意一個,剩下的n-1個線段組成的新的合並線段集數量最大是多少?

思路:

這道題首先想到的是並查集做法,枚舉刪除任意一條線段后,剩下的線段組成的集合是多少,取max,這個復雜度有n2 × 並查集復雜度,顯然是不行的。那么考慮離散化處理線段左右端點,然后去掃描。

 

如圖所示,線段1,2,3,4離散化處理左右端點,然后排個序並標記一下線段號,開始掃描,掃描到的端點先放入multiset集合中去,最初掃描到線段1的左端點L1,然后是L2,再然后是R1,此時我們發現,線段1已經掃描完比,那么刪除這條線段1的左右端點,發現集合中只剩下了L2,且下一個要掃描到的端點是L3,此時就意味着刪除點線段2后,線段1和線段3是不相交的,那么刪除線段2后,新線段合並集合數量就會+1。同理當掃描到R2時,整個線段2已經掃描完畢,刪除集合中線段2左右端點,集合只剩下線段3的左端點,且下一個元素是線段4的左端點,說明線段2和線段4不相交,那么此時刪除線段3,就意味着線段2和線段4不相連,新線段合並集合數量就+1,根據以上這個性質,掃描的時候枚舉下個元素是左端點還是右端點,記錄刪除每個線段刪除后,合並集合會增加多少,最終拿最初不刪除任何線段得到的合並線段集數量+max(刪除某一線段增加的數量)就是答案

當然要特判一種情況:

 

 如圖所示線段1這種情況,刪除這條線段,則新合並集是-1,因為它沒有和任何線段有相交,本身就構成一個獨立的合並線段集,刪除就減少1個合並線段集,特判這種情況即可。

 

AC代碼:

 1 #include<iostream>
 2 #include<vector>
 3 #include<cstdlib>
 4 #include<cstdio>
 5 #include<algorithm>
 6 #include<cmath>
 7 #include<set>
 8 #include<cstring>
 9 #include<queue>
10 #include<map>
11 using namespace std;
12 typedef long long ll;
13 const int maxn = 4e5+10;   
14 pair<ll,ll> p[maxn];
15 int cnt[maxn];
16 int main()
17 {
18     int t;
19     cin>>t;
20     while(t--){
21         int n;
22         cin>>n;
23         for(int i = 1;i<=n;i++){
24             ll l,r;
25             cin>>l>>r;
26             p[2*i-1] = make_pair(l,-i);//離散化記錄區間左右端點的位置和區間標號i 
27             p[2*i] = make_pair(r,i); 
28             cnt[i] = 0;
29         }
30         sort(p+1,p+2*n+1);
31         int ans = 0;
32         multiset<int> s;
33         for(int i = 1;i<=2*n;i++){
34             if(p[i].second < 0){//如果是左端點,就插入set 
35                 s.insert(-p[i].second );
36             }
37             else{
38                 s.erase(s.find(p[i].second));//如果是右端點,就把這個區間刪除 
39             }
40             if(s.size() == 0) ans++;//如果集合是空,記錄一個合並的區間 
41             if(s.size() == 1 && p[i].second > 0 && p[i+1].second < 0 && p[i+1].first > p[i].first ){
42                 cnt[*s.begin()]++;//當前是左端點,但是下個是右端點,cnt++ 
43             }
44             if(s.size() == 1 && p[i].second < 0 && p[i+1].second >0){
45                 cnt[*s.begin()]--;//如果首先插入地是一段單獨區間(l r),去掉這個區間則區間數量-1 
46             }
47         }
48         int t = -1;
49         for(int i = 1;i<=n;i++){
50             t = max(t,cnt[i]);
51         }
52         cout<<ans+t<<endl;
53     }
54     return 0;
55 }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM