ssoj3994: 光线追踪(raytracing)

【题目背景】
初中时的乔猫试着组建了NEWorld开发组,可是不久之后却因为合作上的问题(和乔猫工程水平差,代码混乱的问题),开发组成员之间常常产生矛盾,关系越来越不如以前……一年下来,受到长期挫折的乔猫最终放弃了NEWorld,决定在信息竞赛方面努力奋斗……
又是一年过去,上了高中的乔猫突发奇想,决定自己尝试写一个基于八叉树BVH(空间细分)的光线追踪渲染器。为了向自己的中二时代致敬,渲染的模型也是一个“方块组成的世界”……同样,为了简化,这里只考虑二维的情况……(貌似简化太多了吧233)
【问题描述】
考虑一个二维平面,摄像机在(0,0)的位置,初始时平面上没有障碍物。现在执行?次操作,操作有两种(假设这是第?次操作,1≤?≤?):

  1. 给定?0,?0,?1,?1(?0<?1,?0<?1),创建一个每条边与坐标轴平行的长方形障碍物,包含所有满足?0≤?≤?1且?0≤?≤?1的点(?,?)(如果这个区域的某一部分已经存在障碍,则直接覆盖掉它,具体请看样例)。这个障碍物的编号为?。
  2. 给定向量(?,?),会有一个动点从摄像机所在的(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的范围过大,除完后小数位相似的部分很多吧)。
总的来说,还是我的数据结构太弱了,调了一个下午。。。(联赛之后再好好补一补吧)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值