题意node
给\(n(1\leq n\leq 2*10^5)\)个线段$[l_i,r_i] (1≤l_i≤r_i≤10^9) $,问最少删除几个线段,使得剩下线段中,有至少一个线段与全部线段相交。ios
分析c++
对于线段相交且在线段端点数据范围很大的状况下,第一想法是离散化。数组
若是枚举一个线段和其余全部线段判交,时间复杂度是\(O(n^2)\),显然是没法接受的,考虑如何优化。优化
对于一个左端点为\(l_i\),右端点为\(r_i\)的线段,咱们能够考虑,如有另外一个具备相同左端点,右端点为\(r\),且\(r>r_i\)的线段,取另外一个线段做为交线段更优。spa
那么咱们能够考虑枚举左端点,以上述最大的\(r\)为右端点判交,但如果还与其余全部线段判交,时间复杂度仍然是\(O(n^2)\)。指针
再次考虑优化,因为咱们作法是枚举左端点\(i\),那么随着左端点增大,相交的线段也会变化,咱们考虑这个变化量,将线段排序,这样能够保证在右端点增大时,新增线段在数组中是连续的,这样便可考虑双指针。code
在以前的所取集合中,大部分线段是仍然能够与当前线段相交的,而没法相交的是右端点为\(i-1\)的线段,因此当一条线段加入集合中,在其\(r_i\)上作一个标记,遍历到时减去数字便可。排序
#pragma GCC optimize(3, "Ofast", "inline") #include <bits/stdc++.h> #define start ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); #define ll long long #define ull unsigned long long #define int ll #define ls st<<1 #define rs st<<1|1 #define pii pair<int,int> #define rep(z, x, y) for(int z=x;z<=y;++z) #define repd(z, x, y) for(int z=x;z>=y;--z) #define com bool operator<(const node &b)const using namespace std; mt19937 rnd(chrono::high_resolution_clock::now().time_since_epoch().count()); const int maxn = (ll) 1e6 + 5; const int mod = 1e9 + 7; const int inf = 0x3f3f3f3f; int T = 1; int sum[maxn]; pii a[maxn]; int r[maxn]; void solve() { int n; cin >> n; vector<int> v; rep(i, 1, n) { cin >> a[i].first >> a[i].second; v.push_back(a[i].first); v.push_back(a[i].second); } sort(v.begin(), v.end()); v.erase(unique(v.begin(), v.end()), v.end()); rep(i, 0, v.size())r[i] = sum[i] = 0; rep(i, 1, n) { a[i].first = lower_bound(v.begin(), v.end(), a[i].first) - v.begin() + 1; a[i].second = lower_bound(v.begin(), v.end(), a[i].second) - v.begin() + 1; r[a[i].first] = max(r[a[i].first], a[i].second); } sort(a + 1, a + n + 1); int now = 0; int ans = 1; int pos = 1; rep(i, 0, v.size()) { now -= sum[i - 1]; while (pos <= n) { if (a[pos].first <= r[i]) { ++sum[a[pos].second]; ++pos; ++now; } else break; } ans = max(ans, now); } cout << n - ans << '\n'; } signed main() { start; cin >> T; while (T--) solve(); return 0; }