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
题目大意:
有N条线段,一个线段集合是好的,当且仅当集合中至少存在一条线段能够和集合中所有的线段相交,现在让你删除最少的线段,使得剩下的线段能够构成好的集合,输出最小删除次数。
解法:
问题转换成问你每个线段和多少条线段相交。
首先离散化一下,我们只看每个线段的端点,对于某条线段,区间中出现多少端点代表有多少相交线段,注意如果某条线段两个端点都在里面,答案就不对了,所以我们需要分类,先加左端点,再加右端点。这时候思路已经出来了,按照左右端点各排下序,先访问下每个线段包含了多少左端点,再倒着遍历看包含了多少右端点,中间用树状数组维护即可。
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改宏定义!!!
}