好题 看似线段树的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 }