题目描述
考虑一个二维平面,摄像机在(0,0)(0,0)的位置,初始时平面上没有障碍物。现在执行QQ次操作,操作有两种(假设这是第ii次操作,1≤i≤Q1≤i≤Q):
1、给定x0,y0,x1,y1(x0<x1,y0<y1)x0,y0,x1,y1(x0<x1,y0<y1),创建一个每条边与坐标轴平行的长方形障碍物,包含所有满足x0≤x≤x1x0≤x≤x1且y0≤y≤y1y0≤y≤y1的点(x,y)(x,y)(如果这个区域的某一部分已经存在障碍,则直接覆盖掉它,具体请看样例)。这个障碍物的编号为ii。
2、给定向量(x,y)(x,y),会有一个动点从摄像机所在的(0,0)(0,0)位置出发,以(x,y)(x,y)所指的方向前进,直到碰到第一个障碍物为止。
对于第2种操作,输出最先碰到的障碍物的编号。若不会碰到任何障碍物,输出0。
输入
输入文件第一行一个正整数QQ,表示操作总数。
接下来的QQ行,每行第一个正整数opiopi为操作种类(保证为1或2)。如果为1,则接下来四个正整数x0,y0,x1,y1(x0<x1,y0<y1)x0,y0,x1,y1(x0<x1,y0<y1)表示障碍的位置;如果为2,则接下来两个正整数x,yx,y表示前进方向。
输出
输出文件包含RR行(RR为第2种操作的总数),每行一个正整数,表示第一个碰到的障碍物编号。
样例输入
<span style="color:#333333"><span style="color:#333333">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</span></span>
样例输出
<span style="color:#333333"><span style="color:#333333">1
2
2
5
0</span></span>
提示
样例解释
在9次操作之后,平面的一部分如图所示(箭头为所有第2种操作询问的路线)。
数据范围
对于30% 的数据:Q≤1000Q≤1000。
对于另外30% 的数据:0≤x0,y0,x1,y1,x,y≤2000≤x0,y0,x1,y1,x,y≤200。
对于100% 的数据:Q≤105,0≤x0,y0,x1,y1,x,y≤109,x0<x1,y0<y1Q≤105,0≤x0,y0,x1,y1,x,y≤109,x0<x1,y0<y1;x0x0和y0y0不全为0,xx和yy不全为0。
来源
题解:
一个障碍物可以挡住一个范围以内的斜率,依照这个,我们可以以斜率为下标建立一个线段树,里面维护的是斜率为k第一个遇到的障碍物编号。然而我们可能交一个障碍物于侧面或者下面,所以要把横纵坐标分开维护,开两个线段树维护,具体实现比较繁琐,代码实现能力有待提高。。。。。。。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<map>
#define eps 1e-6
using namespace std;
typedef double db;
map<db,int>dk;
struct Node{int op,x0,y0,x2,y2;}s[100005];
struct node{int l,r,id;double Min;}tre1[1200005],tre2[1200005];
//1 x 2 y
int Q,tot,cnt,iid,mx,my;double xl[500005],vv;
void build(int k,int l,int r)
{
tre1[k].l=tre2[k].l=l;tre1[k].r=tre2[k].r=r;tre1[k].Min=tre2[k].Min=1e18;
if(l==r)return;
int mid=l+r>>1;
build(k*2,l,mid);build(k*2+1,mid+1,r);
}
void update1(int k,int l,int r,int v,int id)
{
if(l<=tre1[k].l&&r>=tre1[k].r)
{
if(v<=tre1[k].Min)tre1[k].Min=v,tre1[k].id=id;
return;
}
int mid=tre1[k].l+tre1[k].r>>1;
if(l<=mid)update1(k*2,l,r,v,id);
if(r>mid)update1(k*2+1,l,r,v,id);
}
void update2(int k,int l,int r,int v,int id)
{
if(l<=tre2[k].l&&r>=tre2[k].r)
{
if(v<=tre2[k].Min)tre2[k].Min=v,tre2[k].id=id;
return;
}
int mid=tre2[k].l+tre2[k].r>>1;
if(l<=mid)update2(k*2,l,r,v,id);
if(r>mid)update2(k*2+1,l,r,v,id);
}
void ask1(int k,int t)
{
if(tre1[k].Min<vv)vv=tre1[k].Min,iid=tre1[k].id;
else if(tre1[k].Min==vv)iid=max(iid,tre1[k].id);
if(tre1[k].l==tre1[k].r)return;
int mid=tre1[k].l+tre1[k].r>>1;
if(t<=mid)ask1(k*2,t);
else ask1(k*2+1,t);
}
void ask2(int k,int t)
{
if(tre2[k].Min<vv)vv=tre2[k].Min,iid=tre2[k].id;
else if(tre2[k].Min==vv)iid=max(iid,tre2[k].id);
if(tre2[k].l==tre2[k].r)return;
int mid=tre2[k].l+tre2[k].r>>1;
if(t<=mid)ask2(k*2,t);
else ask2(k*2+1,t);
}
int main()
{
scanf("%d",&Q);
for(int i=1;i<=Q;++i)
{
scanf("%d",&s[i].op);
if(s[i].op==1)
{
scanf("%d%d%d%d",&s[i].x0,&s[i].y0,&s[i].x2,&s[i].y2);
xl[++tot]=atan2(s[i].y0,s[i].x0);
xl[++tot]=atan2(s[i].y0,s[i].x2);
xl[++tot]=atan2(s[i].y2,s[i].x0);
}
else
{
scanf("%d%d",&s[i].x0,&s[i].y0);
xl[++tot]=atan2(s[i].y0,s[i].x0);
}
}
sort(xl+1,xl+1+tot);
for(int i=1;i<=tot;++i)if(!dk[xl[i]])dk[xl[i]]=++cnt;
build(1,1,cnt);
for(int i=1;i<=Q;++i)
{
if(s[i].op==1)
{
double t1,t2,t3;
t1=dk[atan2(s[i].y0,s[i].x0)];t2=dk[atan2(s[i].y0,s[i].x2)];
t3=dk[atan2(s[i].y2,s[i].x0)];
update1(1,t1,t3,s[i].x0,i);
update2(1,t2,t1,s[i].y0,i);
if(!s[i].x0)
{
if(!mx)mx=i;
if(s[i].y0<=s[mx].y0)mx=i;
}
if(!s[i].y0)
{
if(!my)my=i;
if(s[i].x0<=s[my].x0)my=i;
}
}
else
{
if(!s[i].x0||!s[i].y0)
{
if(!s[i].x0&&s[i].y0)printf("%d\n",mx);
else if(s[i].x0&&!s[i].y0)printf("%d\n",my);
else printf("%d\n",max(mx,my));
continue;
}
double t=dk[atan2(s[i].y0,s[i].x0)];
int iid1,iid2;double xx,kk=(db)s[i].y0/s[i].x0;
vv=1e18;iid=0;ask1(1,t);
iid1=iid;xx=(db)vv;
vv=1e18;iid=0;ask2(1,t);
iid2=iid;
if(!iid1||!iid2){printf("%d\n",iid1+iid2);continue;}
int ans;
vv/=kk;
/*if(vv-xx>-eps)ans=iid1;
else if(xx-vv>-eps)ans=iid2;
else ans=max(iid1,iid2);*/
if(vv>xx||(fabs(vv-xx)<eps&&iid1>iid2)) ans=iid1;
else ans=iid2;
printf("%d\n",ans);
}
}
}