【jzoj2380】【离散化】白板

题目描述

PYWBKTDA有一块白板,这块白板的四条边分别平行于坐标轴。我们可以假设这块白板的左下角在(x 1 ,y 1 )位置,右上角在(x 2 ,y 2 )位置。

现在有两块黑板放到白板的上面,这两块黑板的四条边也是平行于坐标轴的。我们可以设第1块黑板的左下角是(x 3 ,y 3 ),右上角在(x 4 ,y 4 )位置, 第2块黑板的左下角是(x 5 ,y 5 ),右上角在(x 6 ,y 6 )位置。
在这里插入图片描述
现在你的任务是来判断,我们从上往下看,是否有白板的部分区域可以被看到。所谓的白板部分区域被看到的意思是,白板上至少有一个点没有被黑板遮住。

输入

输入第一行有一个整数t,表示数据的组数。
接下来每组数据:
输入的第一行包含4个整数,分别表示x 1 ,y 1 ,x 2 ,y 2 ,即白板的左下角和右上角。
输入的第二行包含4个整数,分别表示x 3 ,y 3 ,x 4 ,y 4 ,即第1块黑板的左下角和右上角。
输入的第三行包含4个整数,分别表示x 5 ,y 5 ,x 6 ,y 6 ,即第2块黑板的左下角和右上角。

输出

输出有t行,对于每组数据,如果有部分白板可以被看到,就输出Y ES,否则就输出NO。

样例输入

3
2 2 4 4
1 1 3 5
3 1 5 5
3 3 7 5
0 0 4 6
0 0 7 4
5 2 10 5
3 1 7 6
8 1 11 7

样例输出

NO
YES
YES
第一个例子中,白板被黑板完全覆盖。
第二个例子中,部分白板可以看到。比如(6.5,4.5)这个点就可以被看到。

数据范围限制

对于50%的数据:
0 ≤ x 1 < x 2 ≤ 100,0 ≤ y 1 < y 2 ≤ 100。
0 ≤ x 3 < x 4 ≤ 100,0 ≤ y 3 < y 4 ≤ 100。
0 ≤ x 5 < x 6 ≤ 100,0 ≤ y 5 < y 6 ≤ 100。
对于100%的数据:
1 ≤ t ≤ 100。
0 ≤ x 1 < x 2 ≤ 10 6 ,0 ≤ y 1 < y 2 ≤ 10 6 。
0 ≤ x 3 < x 4 ≤ 10 6 ,0 ≤ y 3 < y 4 ≤ 10 6 。
0 ≤ x 5 < x 6 ≤ 10 6 ,0 ≤ y 5 < y 6 ≤ 10 6 。


解题思路

首先考虑50分算法:
把白板范围整个标记,然后再把两个黑板范围标记,最后查找白板范围有没有 没被黑板标记的点。很好实现但是100%的数据数组会爆。
100分算法:
离散化处理 (但是我不知道算法原理,建议百度)

离散化处理
把三个板的x坐标和y坐标分别存入x和y数组,从小到大排序,再把坐标替换成坐标的排序结果,就是这个坐标的大小排位,这个排位和平常的考试排位一样。比如:1 2 5 5 7 的名次排序是 1 2 3 3 5


50分算法

#include<iostream>
#include<cstdio>
#include<cstring> 
using namespace std;
int sx,sy,ex,ey,x1,y1,x2,y2;
int a[1000][1000],Gun,T;
int main(){
//freopen("sheet.in","r",stdin);
//freopen("sheet.out","w",stdout);
	scanf("%d",&T);
	while(T-->0){
		memset(a,0,sizeof(a));Gun=0;
		scanf("%d%d%d%d",&sx,&sy,&ex,&ey);
		for(int i=sx;i<=ex-1;i++)//范围这里因为提目需求 面
		    for(int j=sy;j<=ey-1;j++)//但是给的是 点,可以-1(简单粗暴)
			    a[i][j]=1; //标记白板
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		for(int i=x1;i<=x2-1;i++)
		    for(int j=y1;j<=y2-1;j++)
			    a[i][j]=0; //标记黑板
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		for(int i=x1;i<=x2-1;i++)
		    for(int j=y1;j<=y2-1;j++)
			    a[i][j]=0; //标记黑板
		for(int i=sx;i<=ex-1;i++)
		    for(int j=sy;j<=ey-1;j++)
		        Gun+=a[i][j];//查找白板标记
		if(Gun>0)printf("YES\n");else printf("NO\n");
	}
} 

100分做法

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
struct DT{
	int x,v,s;
}x[10],y[10];
int f[5][5],T,Gun,a[10][10];
bool cmp(const DT&k,const DT&l){
	return (k.x<l.x);
}
bool cmp1(const DT&k,const DT&l){
	return (k.x<l.x);
}
void read(){
	memset(a,0,sizeof(a));Gun=0;
	for(int i=1;i<=3;i++){
    	scanf("%d%d%d%d",&f[i][1],&f[i][2],&f[i][3],&f[i][4]);
		x[i].x=f[i][1],x[i].v=1,x[i].s=i;
		//.x存坐标数,用来排序;.v存这个坐标是左下x还是左下y、右上x、右上y
		x[3+i].x=f[i][3],x[3+i].v=3,x[3+i].s=i;
		//+3是因为要存6个,左下x存前三个,右上的x存后三个
		y[i].x=f[i][2],y[i].v=2,y[i].s=i;      // 
		y[3+i].x=f[i][4],y[3+i].v=4,y[3+i].s=i;//同上
	}
}
void demo(){
	x[0].x=y[0].x=-1;
	for(int i=1;i<=6;i++){
		if(x[i].x==x[i-1].x)f[x[i].s][x[i].v]=f[x[i-1].s][x[i-1].v];
		//如果和前一个点一样,就像分数和前一个人一样,就和前一个人的名次相同
		   else f[x[i].s][x[i].v]=i;
		//如果不一样,就和i相等
		if(y[i].x==y[i-1].x)f[y[i].s][y[i].v]=f[y[i-1].s][y[i-1].v];
		   else f[y[i].s][y[i].v]=i;
	}
}
void work(){
        for(int i=f[1][1]+1;i<=f[1][3];i++)
		    for(int j=f[1][2]+1;j<=f[1][4];j++)
		        a[i][j]=1;
		for(int i=f[2][1]+1;i<=f[2][3];i++)
		    for(int j=f[2][2]+1;j<=f[2][4];j++)
		        a[i][j]=0;
		for(int i=f[3][1]+1;i<=f[3][3];i++)
		    for(int j=f[3][2]+1;j<=f[3][4];j++)
		        a[i][j]=0;
		for(int i=f[1][1]+1;i<=f[1][3];i++)
		    for(int j=f[1][2]+1;j<=f[1][4];j++)
		        Gun+=a[i][j];
		if(Gun>0)printf("YES\n");else printf("NO\n");
}
int main(){
freopen("sheet.in","r",stdin);
freopen("sheet.out","w",stdout);
	scanf("%d",&T);
	while(T-->0){
		read();//读入,顺便预处理把坐标存起来
		sort(x+1,x+6+1,cmp); //
		sort(y+1,y+6+1,cmp1);//从小到大排序(我也不知道我为什么要写两个cmp)
		demo();//把坐标替换
		work();//50分的统计
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值