題意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; }