E - Delete a Segment

E - Delete a Segment

https://codeforces.com/contest/1285/problem/E
There are n segments on a Ox axis [l1,r1], [l2,r2], …, [ln,rn]. Segment [l,r] covers all points from l to r inclusive, so all x such that l≤x≤r.

Segments can be placed arbitrarily — be inside each other, coincide and so on. Segments can degenerate into points, that is li=ri is possible.

Union of the set of segments is such a set of segments which covers exactly the same set of points as the original set. For example:

if n=3 and there are segments [3,6], [100,100], [5,8] then their union is 2 segments: [3,8] and [100,100];
if n=5 and there are segments [1,2], [2,3], [4,5], [4,6], [6,6] then their union is 2 segments: [1,3] and [4,6].
Obviously, a union is a set of pairwise non-intersecting segments.

You are asked to erase exactly one segment of the given n so that the number of segments in the union of the rest n−1 segments is maximum possible.

For example, if n=4 and there are segments [1,4], [2,3], [3,6], [5,7], then:

erasing the first segment will lead to [2,3], [3,6], [5,7] remaining, which have 1 segment in their union;
erasing the second segment will lead to [1,4], [3,6], [5,7] remaining, which have 1 segment in their union;
erasing the third segment will lead to [1,4], [2,3], [5,7] remaining, which have 2 segments in their union;
erasing the fourth segment will lead to [1,4], [2,3], [3,6] remaining, which have 1 segment in their union.
Thus, you are required to erase the third segment to get answer 2.

Write a program that will find the maximum number of segments in the union of n−1 segments if you erase any of the given n segments.

Note that if there are multiple equal segments in the given set, then you can erase only one of them anyway. So the set after erasing will have exactly n−1 segments.

Input
The first line contains one integer t (1≤t≤104) — the number of test cases in the test. Then the descriptions of t test cases follow.

The first of each test case contains a single integer n (2≤n≤2⋅105) — the number of segments in the given set. Then n lines follow, each contains a description of a segment — a pair of integers li, ri (−109≤li≤ri≤109), where li and ri are the coordinates of the left and right borders of the i-th segment, respectively.

The segments are given in an arbitrary order.

It is guaranteed that the sum of n over all test cases does not exceed 2⋅105.

Output
Print t integers — the answers to the t given test cases in the order of input. The answer is the maximum number of segments in the union of n−1 segments if you erase any of the given n segments.

题意:有n段闭区间,先要删除其中的一段,将其余的段并起来得到x个不相交的段,问x的最大值
思路:首先,我们很容易求得不删任何一段时不相交的段数,现考虑删除一段时会增加的答案数,先将所有的段离散化(注意因为前一段的结尾和后一段的开始部分如果相邻会有影响,所以得在中间插入一个点),用a数组记录下每个位置现有的段数,很明显当a[i]>1&&a[i-1]<=1时,位置i为一个新的段的开始处且被另一段连接起来的,只要删除那一段答案数就可以加一,将这个结果的前缀和用sum数组记录下来,但是要注意我们只记录了删除一段会有多少个新段开始处被暴露,但还存在一种情况就是删除的那一段左端点处会暴露出一个新段,但没有记录在sum数组中(因为并不是新段开始位置),即a[nod[i].l] > 1 && a[nod[i].l-1] > 1的情况,得加上1,然后因为删除了一段最终结果要减1,这样即可得到答案

#include<bits/stdc++.h>
#define MAXN 200005
using namespace std;
int n,cnt,b[MAXN*6],in[MAXN*6],out[MAXN * 6],a[MAXN*6],sum[MAXN * 6];
struct node
{
	int l,r;
}nod[MAXN];
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		cnt = 0;
		for(int i = 1;i <= n;++i)
		{
			scanf("%d%d",&nod[i].l,&nod[i].r);
			nod[i].l *= 2,nod[i].r *= 2;
			b[++cnt] = nod[i].l,b[++cnt] = nod[i].r;
			b[++cnt] = nod[i].l-1,b[++cnt] = nod[i].l + 1;
			b[++cnt] = nod[i].r-1;b[++cnt] = nod[i].r+1;
		}
		sort(b+1,b+cnt+1);
		cnt = unique(b+1,b+cnt+1)-b;
		memset(in,0,sizeof(int)*(cnt+1));
		memset(out,0,sizeof(int)*(cnt+1));
		for(int i = 1;i <= n;++i)
		{
			nod[i].l = lower_bound(b+1,b+cnt+1,nod[i].l)-b;
			nod[i].r = lower_bound(b+1,b+cnt+1,nod[i].r)-b;
			++in[nod[i].l],++out[nod[i].r];
		}
		a[0] = 0;
		int tmp = 0;
		for(int i = 1;i <= cnt;++i)
		{
			tmp += in[i];
			a[i] = tmp;
			tmp -= out[i];
		}
		int ans = 0;
		sum[0] = 0;
		for(int i = 1;i <= cnt;++i)
		{
			sum[i] = sum[i-1] + (a[i] > 1 && a[i-1] <= 1);
			ans += (a[i] > 0 && a[i-1] == 0);
		}
		int maxn = 0;
		for(int i = 1;i <= n;++i)
		{
			int add = sum[nod[i].r]-sum[nod[i].l-1];
			if(a[nod[i].l] > 1 && a[nod[i].l-1] > 1)
				++add;
			maxn = max(maxn,add);
		}
		printf("%d\n",ans+maxn-1);
	}
	return 0;
}
发布了50 篇原创文章 · 获赞 3 · 访问量 3118

猜你喜欢

转载自blog.csdn.net/xing_mo/article/details/103943554