[JZOJ5039]查询

来源:互联网 发布:微信大屏幕霸屏源码 编辑:程序博客网 时间:2024/06/06 01:39

题目大意

给出平面上的n条线段(用(x1,y1)(x2,y2)表示线段的端点)。
你要支持以下两个操作(总共q个):
 0 (x1,y1) (x2,y2):表示加入一条新的线段
 1 x0:表示询问所有线段中,x坐标在x0处的最高点的y坐标(如果对应位置没有线段则输出0

1n5×104,1m1.5×105,x1,x2,y1,y2,x0Z,0<x0105,|x1|,|x2|,|y1|,|y2|106


题目分析

既然所有坐标都在整点上,而且询问的x0范围在105以内,我们考虑按照x坐标建一棵线段树来处理这些线段。
做模拟赛的时候我想到的一个特别逗的想法是:将所有线段下放到线段树上对应的区间,然后在线段树的每一个节点上用平衡树来维护凸壳。时空复杂度都是O(nlog2n)但是常数巨大,而且有点难打(反正我没有debug出来)。
其实在这题我们没有必要一个节点维护多条线段。考虑使用如下的算法:
先将线段下方到对应的区间上,如果这个区间的节点没有线段,我们就放上去。否则我们就比较一下当前线段和节点上的线段,在上端部分最长的线段储存在这个区间的节点上,短的那一条则递归到其在上面的那一边的子树里面,然后做类似的操作。如果下传到了叶子节点,则直接比较更新即可。
一条线段会下放到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;}
0 0
原创粉丝点击