题目大意
给出平面上的
n
条线段(用
你要支持以下两个操作(总共
q
个):
∙ 1 x0
:表示询问所有线段中,
x
坐标在
1≤n≤5×104,1≤m≤1.5×105,x1,x2,y1,y2,x0∈Z,0<x0≤105,|x1|,|x2|,|y1|,|y2|≤106
题目分析
既然所有坐标都在整点上,而且询问的
x0
范围在
105
以内,我们考虑按照
x
坐标建一棵线段树来处理这些线段。
做模拟赛的时候我想到的一个特别逗的想法是:将所有线段下放到线段树上对应的区间,然后在线段树的每一个节点上用平衡树来维护凸壳。时空复杂度都是
其实在这题我们没有必要一个节点维护多条线段。考虑使用如下的算法:
先将线段下方到对应的区间上,如果这个区间的节点没有线段,我们就放上去。否则我们就比较一下当前线段和节点上的线段,在上端部分最长的线段储存在这个区间的节点上,短的那一条则递归到其在上面的那一边的子树里面,然后做类似的操作。如果下传到了叶子节点,则直接比较更新即可。
一条线段会下放到
logn
个区间上,然后每个区间再向下走
logn
层。时间复杂度
O(nlog2n)
。
代码实现
#include <algorithm>
#include <iostream>
#include <cfloat>
#include <cctype>
#include <cstdio>
using namespace std;
typedef long double db;
int read()
{
int x=0,f=1;
char ch=getchar();
while (!isdigit(ch)) f=ch=='-'?-1:f,ch=getchar();
while (isdigit(ch)) x=x*10+ch-'0',ch=getchar();
return x*f;
}
const db INF=DBL_MAX;
const int X=100000;
struct P
{
db x,y;
P (db x_=0.,db y_=0.){x=x_,y=y_;}
void load(){x=read(),y=read();}
inline P operator+(P const p)const{return P(x+p.x,y+p.y);}
inline P operator-(P const p)const{return P(x-p.x,y-p.y);}
inline P operator*(db const k)const{return P(x*k,y*k);}
};
struct L
{
P p,v;
L (){}
L (P p_,P v_){p=p_,v=v_;}
};
inline P ict(L l,db x0){return l.p+(l.v*((x0-l.p.x)/l.v.x));}
struct segment_tree
{
bool used[X+5<<3];
L seg[X+5<<3];
void modify(int x,int st,int en,int l,int r,L sg)
{
if (st>en) return;
int mid=l+r>>1;
if (st==l&&en==r)
{
if (!used[x]) used[x]=1,seg[x]=sg;
else
{
db midx=(l+r)/2.;
if (ict(seg[x],midx).y<ict(sg,midx).y) swap(sg,seg[x]);
if (ict(seg[x],l).y<ict(sg,l).y) modify(x<<1,l,mid,l,mid,sg);
if (ict(seg[x],r).y<ict(sg,r).y) modify(x<<1|1,mid+1,r,mid+1,r,sg);
}
return;
}
if (en<=mid) modify(x<<1,st,en,l,mid,sg);
else if (mid+1<=st) modify(x<<1|1,st,en,mid+1,r,sg);
else modify(x<<1,st,mid,l,mid,sg),modify(x<<1|1,mid+1,en,mid+1,r,sg);
}
db query(int x,int y,int l,int r)
{
db ret=used[x]?ict(seg[x],y).y:-INF;
if (l==r) return ret;
int mid=l+r>>1;
if (y<=mid) return max(ret,query(x<<1,y,l,mid));
else return max(ret,query(x<<1|1,y,mid+1,r));
}
}t;
db val[X+5];
int n,q;
db ans;
int main()
{
freopen("query.in","r",stdin),freopen("query.out","w",stdout);
n=read(),q=read();
for (int i=1;i<=X;++i) val[i]=-INF;
for (int i=1;i<=n;++i)
{
P u,v;
u.load(),v.load();
if (u.x==v.x) val[(int)u.x]=max(val[(int)u.x],max(u.y,v.y));
else
{
int l=max(1,min((int)u.x,(int)v.x)),r=min(X,max((int)u.x,(int)v.x));
t.modify(1,l,r,1,X,L(u,v-u));
}
}
for (P u,v;q--;)
{
int tp=read(),x;
if (tp) x=read(),ans=max(val[x],t.query(1,x,1,X)),ans>=-1e+6?printf("%.6lf\n",(double)ans):printf("0\n");
else
{
P u,v;
u.load(),v.load();
if (u.x==v.x) val[(int)u.x]=max(val[(int)u.x],max(u.y,v.y));
else
{
int l=max(1,min((int)u.x,(int)v.x)),r=min(X,max((int)u.x,(int)v.x));
t.modify(1,l,r,1,X,L(u,v-u));
}
}
}
fclose(stdin),fclose(stdout);
return 0;
}