基本思路:已知目标线段[0,m],在所有给出线段左端点值小于目标线段左端点值的线段中,选出所对应右端点值最大的点,并用y的值不断更新左端点的值,直到y值大于M,跳出。
在做之前需要预处理一下,将与目标线段无交集的线段全部滤去,并判断给出的左右线段的最右值和最左值是否能将目标线段覆盖。
在做之前需要预处理一下,将与目标线段无交集的线段全部滤去,并判断给出的左右线段的最右值和最左值是否能将目标线段覆盖。
代码如下:
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
struct point
{
int x, y;
} pot[100002];
int cmp(const void *a, const void *b) //先按x的值排序再按y的值排序
{
point *aa = (point *)a;
point *bb = (point *)b;
if(aa->x != bb->x)
return aa->x > bb->x ? 1 : -1;
return aa->y > bb->y ? 1 : -1;
}
int y_cmp(const void *a, const void *b) //按y的值排序
{
point *aa = (point *)a;
point *bb = (point *)b;
return aa->y > bb->y ? 1 : -1;
}
int mem[200002];
int main()
{
#ifdef test
freopen("in.txt", "r", stdin);
#endif
int t, m, i;
scanf("%d", &t);
while(t--)
{
int ct, flagx = 0, flagy = 0;
int mct = 0;
scanf("%d", &m);
for(ct = 0;; ct++)
{
scanf("%d%d", &pot[ct].x, &pot[ct].y);
if(!pot[ct].x && !pot[ct].y)
break;
if(pot[ct].y <= 0 || pot[ct].x >= m) // 若线段在目标线段的两边,直接略去,不存
ct--;
else
{
if(pot[ct].x <= 0) //需要给出的线段的最左端的值有小于0的值
flagx = 1;
if(pot[ct].y >= m) //需要给出的线段的最右端的值有大于M的值
flagy = 1;
}
}
int l = 0, fi = 0;
if(flagx && flagy && ct == 1) //满足条件,且只有一条线段,则直接输出
printf("1\n%d %d\n", pot[0].x, pot[0].y);
else if(flagx && flagy)
{
qsort(pot, ct, sizeof(pot[0]), cmp);
int ff = 0;
while(l < m) //在所有给出线段左端点值x<目标线段左端点值的线段中,选出所对应y最大的点,并用y的值不断更新左端点的值,直到y值大于M,跳出
{
for(i = fi; i < ct; i++)
if(pot[i].x > l && i > 0&& pot[i - 1].y < pot[i].x) //若中间有一段目标线段是所给线段无法覆盖的,则跳出返回0
{
ff = 1;
printf("0\n");
break;
}
else if(pot[i].x > l)
break;
qsort(&pot[fi], i - fi, sizeof(pot[0]), y_cmp); //按y值排序
mem[++mct] = pot[i - 1].x;
mem[++mct] = pot[i - 1].y;
l = pot[i - 1].y;
fi = i;
if(ff)
break;
}
if(ff)
{
puts("");
continue;
}
printf("%d\n", mct / 2);
for(int i = 1; i <= mct; i+=2)
printf("%d %d\n", mem[i], mem[i + 1]);
}
else
printf("0\n");
if(t)
puts("");
}
return 0;
}