【题解】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;
}