【题解】P2434 [SDOI2005]区间

P2434 [SDOI2005]区间

题目描述

现给定n个闭区间[ai, bi],1<=i<=n。这些区间的并可以表示为一些不相交的闭区间的并。你的任务就是在这些表示方式中找出包含最少区间的方案。你的输出应该按照区间的升序排列。这里如果说两个区间[a, b]和[c, d]是按照升序排列的,那么我们有a<=b<c<=d。

请写一个程序:

读入这些区间;

计算满足给定条件的不相交闭区间;

把这些区间按照升序输出。

输入格式

第一行包含一个整数n,3<=n<=50000,为区间的数目。以下n行为对区间的描述,第i行为对第i个区间的描述,为两个整数1<=ai<bi<=1000000,表示一个区间[ai, bi]。

输出格式

输出计算出来的不相交的区间。每一行都是对一个区间的描述,包括两个用空格分开的整数,为区间的上下界。你应该把区间按照升序排序。

输入输出样例

输入 #1

5
5 6
1 4
10 10
6 9
8 10

输出 #1

1 4
5 10

solution1

栈或者理解为差分

栈:起点为左括号,终点为右括号。扫描数轴,遇到左括号入栈,遇到右括号时弹出栈顶左括号。当弹出当前栈顶括号后栈为空时,找到一个答案区间,即为当前栈顶左括号与当前右括号所表示的区间。

注意弹出一对括号并不是表示弹出一段区间,更准确的理解是差分。

差分实现:

#include<cmath>
#include<cstdio>
#include<string>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>

using namespace std;
int n, a[1000010], b[1000010], sum, x, y, maxlen, cnt;
int main(){
	scanf("%d", &n);
	for(int i = 1; i <= n; i++){
		scanf("%d%d", &x, &y);
		a[x]++;b[y]++;
		maxlen = max(maxlen, y);
	}
	for(int i = 1; i <= maxlen; i++){
		if(cnt == 0 && a[i])	printf("%d ", i);
		cnt += a[i] - b[i];
		if(cnt == 0 && b[i])	printf("%d\n", i);
	}
	return 0;
}

solution2

按起点升序排列,扫描即可

#include<cmath>
#include<cstdio>
#include<string>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>

using namespace std;
int n, start, end;
struct line{
	int s, e;
}l[50010];
bool cmp(line a, line b){
	if(a.s == b.s)	return a.e < b.e;
	return a.s < b.s;
}
int main(){
	scanf("%d", &n);
	for(int i = 1; i <= n; i++){
		scanf("%d%d", &l[i].s, &l[i].e);
	}
	sort(l + 1, l + 1 + n, cmp);
	start = l[1].s;
	printf("%d ",start);
	end = l[1].e;
	for(int i = 2; i <= n; i++){
		if(l[i].s > end){
			printf("%d\n", end);
			printf("%d ", l[i].s);
			start = l[i].s;
			end = l[i].e;
		}
		else{
			end = max(end, l[i].e);
		}
	}
	printf("%d\n", end);
	return 0;
}

posted @ 2020-08-12 16:53  _Buffett  阅读(179)  评论(0编辑  收藏  举报