Description
给出m个事件。
1. 在坐标系中给出从(x1,y1)到(x2,y2)的线段
2. 询问当在x坐标为a时,与最低的线段的高度,给出此时y的坐标。
Input
第一行一个整数m,表示事件数。
接下来m行,每行有若干正整数,第一个数D表示事件类型。
若D=1,表示添加一条线段,四个整数x1,y1,x2,y2。
若D=2,接下来一个正整数a,询问在x=a处的答案。
对于100%的数据,1≤m≤200000,1≤x,y,a≤10^9,x1<x2。
Output
如题目所示
【解题报告】
这道题有点像BZOJ3165
我们的方法是用一颗线段树来解决。
线段树维护的是当前区间最优线段的左端点高度和右端点高度。
那么什么是最优线段?
显然,对于一个区间,一定会有许多条完全覆盖这个区间的线段,对于区间内的一些点,它上面最低的直线可能是线段A,而对于区间内的另外一些点,它上面最低的直线可能是线段B,线段C。。。。我们维护这个区间时不可能将这些直线全部记录,所以我们钦定一条最优线段,也就是这条线段可以覆盖这一段区间尽可能多的点。
怎么更新呢?
如果我们插入一条线段,如果在当前区间中,它的左右端点都在区间的最优线段之上,那它一定是不优的。如果在当前区间中,它的左右端点都在区间的最优线段之下,那它直接成为当前区间的左右线段。
如果相交的话,就需要分情况讨论它是否能取代最优线段了。
怎么查询呢?
这个很好想,我们二分递归查找所有覆盖查询点的线段,不断更新答案就可以了。
(因为我们在查询的过程中会遍历所有可能成为最优线段的线段)
注意要动态开点
代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int m,root,tn;
const int maxn=200010,maxlog=30,inf=1000000000;
const double eps=1e-8;
struct Node
{
int L,R;
double lv,rv;
}tree[maxn*maxlog];
double get(int x,int X1,double V1,int X2,double V2)
{
return (V2-V1)*(x-X1)/(X2-X1)+V1;
}
int modify(int cur,int l,int r,int x1,double v1,int x2,double v2)
{
if(!cur)
{
cur=++tn;
tree[cur].lv=tree[cur].rv=inf;
}
int mid=(l+r)>>1;
if(x1<=l&&x2>=r)
{
double lv=get(l,x1,v1,x2,v2),rv=get(r,x1,v1,x2,v2);
double sl=lv-tree[cur].lv,sr=rv-tree[cur].rv;
if(sl<=eps&&sr<=eps){tree[cur].lv=lv;tree[cur].rv=rv;return cur;}
if(sl>=-eps&&sr>=-eps) return cur;
if(fabs(sl)<fabs(sr))
{
if(sr<=eps)
{
tree[cur].L=modify(tree[cur].L,l,mid,l,tree[cur].lv,r,tree[cur].rv);
tree[cur].lv=lv;
tree[cur].rv=rv;
}
else tree[cur].L=modify(tree[cur].L,l,mid,x1,v1,x2,v2);
}
else
{
if(sl<=eps)
{
tree[cur].R=modify(tree[cur].R,mid+1,r,l,tree[cur].lv,r,tree[cur].rv);
tree[cur].lv=lv;
tree[cur].rv=rv;
}
else tree[cur].R=modify(tree[cur].R, mid+1, r, x1, v1, x2, v2);
}
}
else
{
if(x1<=mid) tree[cur].L=modify(tree[cur].L,l,mid,x1,v1,x2,v2);
if(x2>mid) tree[cur].R=modify(tree[cur].R,mid+1,r,x1,v1,x2,v2);
}
return cur;
}
double query(int cur,int l,int r,int pos)
{
if(!cur) return inf;
if(l==r) return tree[cur].lv;
int mid=(l+r)>>1;
double ans=get(pos,l,tree[cur].lv,r,tree[cur].rv);
if(pos<=mid) return min(ans,query(tree[cur].L,l,mid,pos));
else return min(ans,query(tree[cur].R,mid+1,r,pos));
}
int main()
{
freopen("defense.in","r",stdin);
freopen("defense.out","w",stdout);
scanf("%d",&m);
int x1,x2;
double v1,v2;
while(m--)
{
int opt;scanf("%d",&opt);
if(opt==1)
{
scanf("%d%lf%d%lf",&x1,&v1,&x2,&v2);
root=modify(root,1,inf,x1,v1,x2,v2);
}
if(opt==2)
{
scanf("%d",&x1);
printf("%lf\n",query(root,1,inf,x1));
}
}
return 0;
}