题目背景

  初中时的乔猫试着组建了$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. vim中代码按照行对齐。

    在vim下, 用命令v, 然后移动光标,选种你的文本, 然后按下=键, 看看效果如何吧.

  2. rebtree学习

    http://www.cnblogs.com/skywang12345/p/3245399.html http://www.cnblogs.com/skywang12345/p/3624177.htm ...

  3. kafka 教程(三)-远程访问

    远程连接 kafka 配置 默认的 kafka 配置是无法远程访问的,解决该问题有几个方案. 方案1 advertised.listeners=PLAINTEXT://IP:9092 注意必须是 ip ...

  4. spring boot 是如何利用jackson进行序列化的?

    接上一篇:spring boot 是如何利用jackson进行反序列化的? @RestController public class HelloController { @RequestMapping ...

  5. npm学习(三)之如何安装本地包、更新本地安装的包、卸载本地安装的包

    如何安装本地包 有两种方式用来安装 npm 包:本地安装和全局安装.至于选择哪种方式来安装,取决于我们如何使用这个包. 如果你自己的模块依赖于某个包,并通过 Node.js 的 require 加载, ...

  6. flutter-dart语言初识

    dart 官方文档 http://dart.goodev.org/guides/language/language-tour# 重要概念所以能够使用变量引用的都是对象,也就是所以可以赋值给变量的都是对 ...

  7. Linux文件读写笔记

    读文件: #include <stdio.h> #include <stdlib.h> #include <unistd.h> //linux下面的头文件 #inc ...

  8. 一文看懂HttpServletResponse

    https://www.jianshu.com/p/8bc6b82403c5 Web服务器收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的request对象.和代表响应的resp ...

  9. Vue Cli 移动端开发

    一.

  10. Linux RAID磁盘阵列

    RAID磁盘阵列 什么是RAID RAID是磁盘阵列的英文缩写,多块磁盘组成了一个组合,一起完成存储任务,就是磁盘阵列. RAID几种常用的类别(组合) RAID0:条带卷:最低磁盘个数2+,空间利用 ...