【题目背景】
初中时的乔猫试着组建了NEWorld开发组,可是不久之后却因为合作上的问题(和乔猫工程水平差,代码混乱的问题),开发组成员之间常常产生矛盾,关系越来越不如以前……一年下来,受到长期挫折的乔猫最终放弃了NEWorld,决定在信息竞赛方面努力奋斗……
又是一年过去,上了高中的乔猫突发奇想,决定自己尝试写一个基于八叉树BVH(空间细分)的光线追踪渲染器。为了向自己的中二时代致敬,渲染的模型也是一个“方块组成的世界”……同样,为了简化,这里只考虑二维的情况……(貌似简化太多了吧233)
【问题描述】
考虑一个二维平面,摄像机在(0,0)的位置,初始时平面上没有障碍物。现在执行?次操作,操作有两种(假设这是第?次操作,1≤?≤?):
- 给定?0,?0,?1,?1(?0<?1,?0<?1),创建一个每条边与坐标轴平行的长方形障碍物,包含所有满足?0≤?≤?1且?0≤?≤?1的点(?,?)(如果这个区域的某一部分已经存在障碍,则直接覆盖掉它,具体请看样例)。这个障碍物的编号为?。
- 给定向量(?,?),会有一个动点从摄像机所在的(0,0)位置出发,以(?,?)所指的方向前进,直到碰到第一个障碍物为止。
对于第2种操作,输出最先碰到的障碍物的编号。若不会碰到任何障碍物,输出0。
【输入格式】
输入文件名为raytracing.in。
输入文件第一行一个正整数Q,表示操作总数。
接下来的Q行,每行第一个正整数???为操作种类(保证为1或2)。如果为1,则接下来四个正整数?0,?0,?1,?1(?0<?1,?0<?1)表示障碍的位置;如果为2,则接下来两个正整数?,?表示前进方向。
【输出格式】
输出文件名为raytracing.out。
输出文件包含?行(?为第2种操作的总数),每行一个正整数,表示第一个碰到的障碍物编号。
全国信息学奥林匹克联赛(NOIP)复赛 提高组 模拟赛
第 7 页 共 7 页
【输入输出样例1】
raytracing.in
raytracing.out
10
1 3 3 10 4
1 4 2 5 6
2 6 2
1 2 8 4 10
1 0 6 3 9
2 5 2
2 8 6
2 2 9
2 4 7
1 5 7 10 10
1
2
2
5
0
【输入输出样例1说明】
在9次操作之后,平面的一部分如图所示(箭头为所有第2种操作询问的路线)。
【输入输出样例2】见选手目录下的
raytracing/raytracing2.in和raytracing/raytracing2.ans。
【数据规模与约定】
对于30% 的数据:?≤1000。
对于另外30% 的数据:0≤?0,?0,?1,?1,?,?≤200。
对于100% 的数据:?≤105,0≤?0,?0,?1,?1,?,?≤109,?0<?1,?0<?1;?0和?0不全为0,?和?不全为0。
题解:
考虑暴力,对于每一个询问,暴力搜索每一个矩形,判断是否能相撞,并取最小值的点的编号。
考虑正解,对于每一个询问要用O(logn)的效率内查询,那么直接按题意模拟是无法做到的,故考虑对题意进行变形。发现每一个矩形能造成的影响一定只有左边和下面的那两条边,而这两条边只要记录下编号后就相互独立,故将这两条边分开看。所以问题就转化为对每一个向量,求它与若干条平行于x轴的线段(平行于y轴同理)在有交点的情况下距离/值。
因为是条件下的最值,而这个条件又类似于区间的东西,故考虑线段树维护。首先要将有交点的条件转化为区间,考虑向量与一边有交点的情况一定是向量的斜率在一个范围内,故每条线段对应一个区间(需要按两两叉积的正负性排序,排序后的编号对应原来的编号,这样可以避免出现小数),然后区间修改,单点查询即可。
这题的实现宏观上并不复杂,但细节较多:首先要注意值相同的要取编号大的,故在判断时还要加上值相等且编号较大的条件(一开始改成>=,这样是错的,因为编号不单调);其次要特判在x,y轴上的情况,因为按原来那样会导致值都为0,故要记录下这种情况下的最值;最后在比较两个答案除以值的时候要开long double且不用加eps(大概是因为x,y的范围过大,除完后小数位相似的部分很多吧)。
总的来说,还是我的数据结构太弱了,调了一个下午。。。(联赛之后再好好补一补吧)。