CF 1285E Delete a Segment

好题  看似线段树的nlogn 实则是multiset + pair

 1 #include<bits/stdc++.h>
 2 #define fi first
 3 #define se second
 4 #define ll long long
 5 using namespace std;
 6 const int N = 2e5 + 10;
 7 pair<int, int> a[N << 1];
 8 int del[N];//del[i]表示删除第i个区间新增的union数 
 9 int main(){
10     ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
11     int T; cin >> T;
12     while(T--)
13     {
14         int n; cin >> n;
15         for(int i = 1 ; i <= n ; i++){
16             int l, r; cin >> l >> r;    
17             a[i * 2 - 1] = {l, -i};
18             a[i * 2] = {r, i};
19             //对于相同位置x的端点,经过排序后左端点将会先被枚举到 
20             del[i] = 0;
21         }
22         sort(a + 1, a + n * 2 + 1);
23         multiset<int> s;
24         int ans1 = 0;//一个都不删对应的union数 
25         for(int i = 1 ; i <= n * 2 ; i++){
26             if(a[i].se < 0)    s.insert(-a[i].se);//左端点插入 
27             else    s.erase(s.find(a[i].second));//如果当前i对应右端点,则删除对应的左端点 
28             if(s.size() == 0)    ans1++;
29             if(s.size() == 1 && a[i].se > 0 && a[i + 1].se < 0 && a[i + 1].fi > a[i].fi)
30                 del[*s.begin()]++;//当前为右端点且可匹配且下一个为左端点且位于当前右侧 
31                 //则删除s中剩余的左端点对应线段必定在*处产生新空隙
32                 //(size为1必定只剩下左端点)        [ [ ]*[
33             if(s.size() == 1 && a[i].se < 0 && a[i + 1].se > 0)
34                 del[*s.begin()]--;//单一线段 
35         }
36         int ans2 = INT_MIN;
37         for(int i = 1 ; i <= n ; i++){
38             ans2 = max(ans2, del[i]);
39         }
40         cout << ans1 + ans2 << endl;
41     }
42     return 0;
43 }
原文地址:https://www.cnblogs.com/ecustlegendn324/p/14277991.html