题目背景

  初中时的乔猫试着组建了$NEWorld$开发组,可是不久之后却因为合作上的问题(和乔猫工程水平差,代码混乱的问题),开发组成员之间常常产生矛盾,关系越来越不如以前......一年下来,受到长期挫折的乔猫最终放弃了$NEWorld$,决定在信息竞赛方面努力奋斗......
  是一年过去,上了高中的乔猫突发奇想,决定自己尝试写一个基于八叉树$BVH$(空间细分)的光线追踪渲染器。为了向自己的中二时代致敬,渲染的模型也是一个“方块组成的世界”......同样,为了简化,这里只考虑二维的情况......(貌似简化太多了吧$233$)


题目描述

  考虑一个二维平面,摄像机在$(0,0)$的位置,初始时平面上没有障碍物。现在执行$Q$次操作,操作有两种(假设这是第$i$次操作,$1\leqslant i\leqslant Q$):
  $1.$给定$x_0,y_0,x_1,y_1(x_0<x_1,y_0<y_1)$,创建一个每条边与坐标轴平行的长方形障碍物,包含所有满足$x_0\leqslant x\leqslant x_1$且$y_0\leqslant y\leqslant y_1$的点$(x,y)$(如果这个区域的某一部分已经存在障碍,则直接覆盖掉它,具体请看样例)。这个障碍物的编号为$i$。
  $2.$给定向量$(x,y)$,会有一个动点从摄像机所在的$(0,0)$位置出发,以$(x,y)$所指的方向前进,直到碰到第一个障碍物为止。
  对于第$2$种操作,输出最先碰到的障碍物的编号。若不会碰到任何障碍物,输出$0$。


输入格式

  输入文件名为$raytracing.in$。
  输入文件第一行一个正整数$Q$,表示操作总数。
  接下来的$Q$行,每行第一个正整数$op_i$为操作种类(保证为$1$或$2$)。如果为$1$,则接下来四个正整数$x_0,y_0,x_1,y_1(x_0<x_1,y_0<y_1)$表示障碍的位置;如果为 $2$,则接下来两个正整数$x,y$表示前进方向。


输出格式

  输出文件名为$raytracing.out$。
  输出文件包含$R$行($R$为第$2$种操作的总数),每行一个正整数,表示第一个碰到的障碍物编号。


样例

样例输入:

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


数据范围与提示

样例解释:

  在$9$次操作之后,平面的一部分如图所示(箭头为所有第$2$种操作询问的路线)。

数据范围:

  对于$30\%$的数据:$Q\leqslant 1,000$。
  对于另外$30\%$的数据:$0\leqslant x_0,y_0,x_1,y_1,x,y\leqslant 200$。
  对于$100\%$的数据:$Q\leqslant 10^5,0\leqslant x_0,y_0,x_1,y_1,x,y\leqslant 10^9,x_0<x_1,y_0<y_1;x_0$和$y_0$不全为$0$,$x$和$y$不全为$0$。


题解

撞上无非就分两种情况:

  $\alpha.$撞底下。

  $\beta.$撞左边。

那么开两棵线段树分别维护最早的撞上的是哪个就好了。

注意斜率是$90$度的时候不要除$0$,还有如果同时撞上多个的话输出编号最大的就好了(我也不知道为什么额……)

时间复杂度:$\Theta(Q\log Q)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
#define L(x) x<<1
#define R(x) x<<1|1
using namespace std;
const double eps=-1e-5;
struct rec{int opt,x0,y0,x2,y2;}e[100001];
map<double,int> mp;
int Q;
int cnt,top;
pair<int,int> tr[400001][2],ansx,ansy;
double slope[300001];
double getslope(int x,int y){return x?(double)y/x:0x3f3f3f3f;}
void build(int x,int l,int r)
{
tr[x][0].first=tr[x][1].first=0x3f3f3f3f;
if(l==r)return;
int mid=(l+r)>>1;
build(L(x),l,mid);
build(R(x),mid+1,r);
}
void add(int x,int l,int r,int L,int R,int w,int id,int p)
{
if(r<L||R<l)return;
if(L<=l&&r<=R){if(w<=tr[x][p].first)tr[x][p]=make_pair(w,id);return;}
int mid=(l+r)>>1;
add(L(x),l,mid,L,R,w,id,p);
add(R(x),mid+1,r,L,R,w,id,p);
}
void ask(int x,int l,int r,int k)
{
if(tr[x][0].first<ansx.first)ansx=tr[x][0];
if(tr[x][0].first==ansx.first)ansx.second=max(ansx.second,tr[x][0].second);
if(tr[x][1].first<ansy.first)ansy=tr[x][1];
if(tr[x][1].first==ansy.first)ansy.second=max(ansy.second,tr[x][1].second);
if(l==r)return;
int mid=(l+r)>>1;
if(k<=mid)ask(L(x),l,mid,k);
else ask(R(x),mid+1,r,k);
}
int main()
{
scanf("%d",&Q);
for(int i=1;i<=Q;i++)
{
scanf("%d",&e[i].opt);
if(e[i].opt==1)
{
scanf("%d%d%d%d",&e[i].x0,&e[i].y0,&e[i].x2,&e[i].y2);
slope[++top]=getslope(e[i].x0,e[i].y0);
slope[++top]=getslope(e[i].x2,e[i].y0);
slope[++top]=getslope(e[i].x0,e[i].y2);
}
if(e[i].opt==2)
{
scanf("%d%d",&e[i].x0,&e[i].y0);
slope[++top]=getslope(e[i].x0,e[i].y0);
}
}
sort(slope+1,slope+top+1);
for(int i=top;i;i--)
{
if(!mp[slope[i]])cnt++;
mp[slope[i]]=cnt;
}
build(1,1,cnt);
for(int i=1;i<=Q;i++)
{
if(e[i].opt==1)
{
add(1,1,cnt,mp[getslope(e[i].x0,e[i].y0)],mp[getslope(e[i].x2,e[i].y0)],e[i].y0,i,0);
add(1,1,cnt,mp[getslope(e[i].x0,e[i].y2)],mp[getslope(e[i].x0,e[i].y0)],e[i].x0,i,1);
}
else
{
ansx=ansy=make_pair(0x3f3f3f3f,0);
ask(1,1,cnt,mp[getslope(e[i].x0,e[i].y0)]);
if(!ansx.second||!ansy.second)printf("%d\n",ansx.second+ansy.second);
else
{
if(!getslope(e[i].x0,e[i].y0))
{
if(e[ansx.second].x0<e[ansy.second].x0||ansx.second<ansy.second)printf("%d\n",ansx.second);
else printf("%d\n",ansy.second);continue;
}
if(getslope(e[i].x0,e[i].y0)==0x3f3f3f3f)
{
if(e[ansx.second].y0<e[ansy.second].y0||ansx.second<ansy.second)printf("%d\n",ansx.second);
else printf("%d\n",ansy.second);continue;
}
if(ansx.first==ansy.first*getslope(e[i].x0,e[i].y0))printf("%d\n",max(ansx.second,ansy.second));
if(ansx.first<ansy.first*getslope(e[i].x0,e[i].y0))printf("%d\n",ansx.second);
if(ansx.first>ansy.first*getslope(e[i].x0,e[i].y0))printf("%d\n",ansy.second);
}
}
}
return 0;
}

rp++

[CSP-S模拟测试]:光线追踪(线段树)的更多相关文章

  1. 【bzoj3638】Cf172 k-Maximum Subsequence Sum 模拟费用流+线段树区间合并

    题目描述 给一列数,要求支持操作: 1.修改某个数的值 2.读入l,r,k,询问在[l,r]内选不相交的不超过k个子段,最大的和是多少. 输入 The first line contains inte ...

  2. 【8.26校内测试】【重构树求直径】【BFS模拟】【线段树维护DP】

    题目性质比较显然,相同颜色联通块可以合并成一个点,重新建树后,发现相邻两个点的颜色一定是不一样的. 然后发现,对于一条链来说,每次把一个点反色,实际上使点数少了2个.如下图 而如果一条链上面有分支,也 ...

  3. [CSP-S模拟测试]:影魔(树状数组+线段树合并)

    题目背景 影魔,奈文摩尔,据说有着一个诗人的灵魂.事实上,他吞噬的诗人灵魂早已成千上万.千百年来,他收集了各式各样的灵魂,包括诗人.牧师.帝王.乞丐.奴隶.罪人,当然,还有英雄.每一个灵魂,都有着自己 ...

  4. BZOJ2040[2009国家集训队]拯救Protoss的故乡——模拟费用流+线段树+树链剖分

    题目描述 在星历2012年,星灵英雄Zeratul预测到他所在的Aiur行星在M天后会发生持续性暴雨灾害,尤其是他们的首都.而Zeratul作为星灵族的英雄,当然是要尽自己最大的努力帮助星灵族渡过这场 ...

  5. 2018.10.20 NOIP模拟 蛋糕(线段树+贪心/lis)

    传送门 听说是最长反链衍生出的对偶定理就能秒了. 本蒟蒻直接用线段树模拟维护的. 对于第一维排序. 维护第二维的偏序关系可以借助线段树/树状数组维护逆序对的思想建立权值线段树贪心求解. 代码

  6. CF280D-k-Maximum Subsequence Sum【模拟费用流,线段树】

    正题 题目链接:https://www.luogu.com.cn/problem/CF280D 题目大意 一个长度为\(n\)的序列,\(m\)次操作 修改一个数 询问一个区间中选出\(k\)段不交子 ...

  7. 【NOIP模拟】board(线段树维护二进制,树序号化为二进制)

    题目背景 SOURCE:NOIP2016-RZZ-2 T3 题目描述 给出这样一棵“二叉树”: 每个节点有左右两个儿子,并如下定义每个节点的高度:假设父亲节点的高度为 h ,那么他的两个儿子的节点的高 ...

  8. BZOJ.3638.CF172 k-Maximum Subsequence Sum(模拟费用流 线段树)

    题目链接 各种zz错误..简直了 /* 19604kb 36292ms 题意:选$k$段不相交的区间,使其权值和最大. 朴素线段树:线段树上每个点维护O(k)个信息,区间合并时O(k^2),总O(mk ...

  9. 2018.06.26 NOIP模拟 纪念碑(线段树+扫描线)

    题解: 题目背景 SOURCE:NOIP2015−GDZSJNZXSOURCE:NOIP2015-GDZSJNZXSOURCE:NOIP2015−GDZSJNZX(难) 题目描述 2034203420 ...

随机推荐

  1. win10的64位操作系统安装Oracle、Sql数据库遇到的问题及解决

    因为工作需要,在重新安装操作系统(Win10)不久的电脑上安装Oracle的客户端(win32_11g)和PLSQL,这个本来就比较复杂,下面记录一下遇到的问题及解决方法. 我有储备多个Oracle的 ...

  2. numpy数组的索引和切片

    numpy数组的索引和切片 基本切片操作 >>> import numpy as np >>> arr=np.arange(10) >>> arr ...

  3. rk3288 编译应用程序

    一. Android.mk 1.1. 什么是.mk Android.mk是Android提供的一个makefile文件,可以将源文件分组为模块.用来引用的头文件目录.需要编译的*.c/*.cpp文件. ...

  4. 最长不下降/不上升子序列&&最长上升/下降子序列

    最长不下降/不上升子序列&&最长上升/下降子序列 struct cmp1{bool operator()(int a,int b){return a>b;}}; int main ...

  5. python简介与简单入门

    1.计算机基础 计算机组成: 输入输出设备内. 存储器 .cpu .电源 .显卡 中央处理器(cpu) 处理各种数据 相当于人的大脑 内存 存储数据 相当于临时记忆 硬盘 存储数据 相当于人的永久记忆 ...

  6. 3种Redis分布式锁的对比

    我们通常使用的synchronized或者Lock都是线程锁,对同一个JVM进程内的多个线程有效.因为锁的本质 是内存中存放一个标记,记录获取锁的线程是谁,这个标记对每个线程都可见.然而我们启动的多个 ...

  7. 如何使用前端分页框架bootstrap paginator

    前端分页框架bootstrap paginator用于web前端页面快速实现美观大方的翻页功能.在实现交互良好的页面翻页功能时,往往还需要配合使用后端分页框架pagehelper.pagehelper ...

  8. express-handlebars

    https://www.npmjs.com/package/express-handlebars

  9. XXE漏洞攻击与防御

    转自https://www.jianshu.com/p/7325b2ef8fc9 0x01 XML基础 在聊XXE之前,先说说相关的XML知识吧. 定义 XML用于标记电子文件使其具有结构性的标记语言 ...

  10. MySQL8连接数据库

    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://127. ...