F. The Treasure of The Segments
time limit per test
3 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
Polycarp found nn segments on the street. A segment with the index ii is described by two integers lili and riri — coordinates of the beginning and end of the segment, respectively. Polycarp realized that he didn't need all the segments, so he wanted to delete some of them.
Polycarp believes that a set of kk segments is good if there is a segment [li,ri][li,ri] (1≤i≤k1≤i≤k) from the set, such that it intersects every segment from the set (the intersection must be a point or segment). For example, a set of 33 segments [[1,4],[2,3],[3,6]][[1,4],[2,3],[3,6]] is good, since the segment [2,3][2,3] intersects each segment from the set. Set of 44 segments [[1,2],[2,3],[3,5],[4,5]][[1,2],[2,3],[3,5],[4,5]] is not good.
Polycarp wonders, what is the minimum number of segments he has to delete so that the remaining segments form a good set?
Input
The first line contains a single integer tt (1≤t≤2⋅1051≤t≤2⋅105) — number of test cases. Then tt test cases follow.
The first line of each test case contains a single integer nn (1≤n≤2⋅1051≤n≤2⋅105) — the number of segments. This is followed by nn lines describing the segments.
Each segment is described by two integers ll and rr (1≤l≤r≤1091≤l≤r≤109) — coordinates of the beginning and end of the segment, respectively.
It is guaranteed that the sum of nn for all test cases does not exceed 2⋅1052⋅105.
Output
For each test case, output a single integer — the minimum number of segments that need to be deleted in order for the set of remaining segments to become good.
Example
input
Copy
4 3 1 4 2 3 3 6 4 1 2 2 3 3 5 4 5 5 1 2 3 8 4 5 6 7 9 10 5 1 5 2 4 3 5 3 8 4 8
output
Copy
0 1 2 0
Main idea:
There are N line segments, a line segment set is good, if and only if there is at least one line segment in the set that can intersect all the line segments in the set, now let you delete the fewest line segments so that the remaining line segments can form a good set. Output the minimum number of deletions.
solution:
The question is transformed into asking you how many line segments intersect each line segment.
First of all discretize, we only look at the endpoints of each line segment. For a certain line segment, how many endpoints appear in the interval represents how many intersecting line segments. Note that if both endpoints of a certain line segment are inside, the answer is wrong , so we need For classification, add the left end point first, and then add the right end point. At this time, the idea has come out. According to the order of the left and right endpoints, first visit how many left endpoints each line segment contains, and then traverse backwards to see how many right endpoints are included, and maintain it with a tree array in the middle.
Accepted code
#pragma GCC optimize(3)
#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;
#define sc scanf
#define Min(x, y) x = min(x, y)
#define Max(x, y) x = max(x, y)
#define ALL(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
#define pir pair <int, int>
#define MK(x, y) make_pair(x, y)
#define MEM(x, b) memset(x, b, sizeof(x))
#define MPY(x, b) memcpy(x, b, sizeof(x))
#define lowbit(x) ((x) & -(x))
#define P2(x) ((x) * (x))
typedef long long ll;
const int Mod = 1e9 + 7;
const int N = 2e5 + 100;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
inline ll dpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t) % Mod; b >>= 1; t = (t*t) % Mod; }return r; }
inline ll fpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t); b >>= 1; t = (t*t); }return r; }
struct node
{
int l, r;
bool operator < (const node &oth) const {
if (r == oth.r)
return l < oth.l;
else
return r < oth.r;
}
}a[N];
int s[N * 2], ans[N], n, sz;
vector <int> ver;
void Init() {
for (int i = 1; i <= sz; i++)
s[i] = 0;
ver.clear();
}
void Add(int x, int v) {
while (x <= sz)
s[x] += v, x += lowbit(x);
}
int Ask(int x) {
int tot = 0;
while (x)
tot += s[x], x -= lowbit(x);
return tot;
}
int Rg_Ask(int l, int r) {
return Ask(r) - Ask(l - 1);
}
int main()
{
#ifdef OlaMins
freopen("D:/input.txt", "r", stdin);
//freopen("D:/output.txt", "w", stdout);
#endif
int T; cin >> T;
while (T--) {
sc("%d", &n);
Init();
for (int i = 1; i <= n; i++) {
int l, r;
sc("%d %d", &l, &r);
ver.push_back(l), ver.push_back(r);
a[i] = { l, r }, ans[i] = 0;
}
sort(ALL(ver));
ver.erase(unique(ALL(ver)), ver.end()); // 离散化
sz = SZ(ver);
for (int i = 1; i <= n; i++) {
a[i].l = lower_bound(ALL(ver), a[i].l) - ver.begin() + 1;
a[i].r = lower_bound(ALL(ver), a[i].r) - ver.begin() + 1;
}
sort(a + 1, a + n + 1);
for (int i = 1; i <= n; i++) { // 先左
int l = a[i].l, r = a[i].r;
ans[i] = Rg_Ask(l, r);
Add(r, 1);
}
for (int i = 1; i <= sz; i++)
s[i] = 0;
int mi = INF;
for (int i = n; i >= 1; i--) { // 后右
int l = a[i].l, r = a[i].r;
ans[i] += Rg_Ask(l, r);
Min(mi, n - ans[i]);
Add(l, 1);
}
printf("%d\n", mi - 1);
}
return 0; // 改数组大小!!!用pair改宏定义!!!
}