【NOI2017模拟4.2】查询【线段树】

来源:互联网 发布:eureka java demo 编辑:程序博客网 时间:2024/04/30 14:05

Description

给出若干条线段,用(x1,y1),(x2,y2)表示其两端点坐标,现在要求支持两种操作:
0 x1 y1 x2 y2
表示加入一条新的线段,(x1,y1)-(x2,y2)
1 x0
询问所有线段中,x坐标在x0处的最高点的y坐标是什么,如果对应位置没有线段,则输出0。

Solution

这题一看就是用线段树做的。但是问题就是怎么维护。
很明显我们要在区间维护一条直线。
但是如果有一条直线交了过去该怎么办?
假设我们现在要修改[l,r]这个区间,我们先在线段树上找到对应的子区间,然后这个子区间会有一条线段。
假设我们当前的线段可以完全高于这个区间上的线段,那么直接更新这个值。
否则:
我们设当前这条线段为a,区间维护的线段为b
如果mid在交点的左边:如果a在[l,mid]可以覆盖,那么把a和b交换(就是把当前线段改为b,维护线段改为a),然后向右继续搜。如果在[l,mid]没有覆盖,那么直接往右搜。
如果mid在交点的右边:如果a在[mid+1,r]可以覆盖,那么把a和b交换,然后向左继续搜。如果在[mid+1,r]没有覆盖,那么直接往左搜。
这样的时间复杂度是O(nlog2n)

Code

#include<iostream>#include<stdio.h>#include<string.h>#include<algorithm>#include<math.h>#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;const int maxn=2e5+7,mxx=1e6+maxn,inf=0x7fffffff;typedef double db;struct nod{    db p,q;}t[mxx*4];int i,j,k,l,n,m,num,x,y,xx,yy,ha,da;bool bz[maxn];db ans,kk,o,yi,er;void change(int x,int l,int r,int y,int z,db p,db q){    if(l==y&&r==z){        if(x==1572969){            o=o;        }        if(l==r||(db)(t[x].p-p)*(t[x].p+(r-l)*t[x].q-p-(r-l)*q)>0.0){            if(p>t[x].p)t[x].p=p,t[x].q=q;            return;        }        int mid=(l+r)/2;        yi=(db)t[x].p+(mid-l)*t[x].q;        er=(db)p+(mid-l)*q;        if((t[x].p-p)*(yi-er)>0){            if(er>yi){                swap(t[x].p,p),swap(t[x].q,q);                change(x*2+1,mid+1,r,mid+1,z,p+q*(mid-y+1),q);            }            else{                change(x*2+1,mid+1,r,mid+1,z,p+q*(mid-y+1),q);            }        }        else{            if(er>yi){                swap(t[x].p,p),swap(t[x].q,q);                change(x*2,l,mid,y,mid,p,q);            }            else{                change(x*2,l,mid,y,mid,p,q);              //  change(x*2+1,mid+1,r,mid+1,z,p+q*(mid-y+1),q);            }        }        return;    }    int mid=(l+r)/2;    if(z<=mid)change(x*2,l,mid,y,z,p,q);    else if(y>mid)change(x*2+1,mid+1,r,y,z,p,q);    else{        change(x*2,l,mid,y,mid,p,q);        change(x*2+1,mid+1,r,mid+1,z,p+q*(mid-y+1),q);    }}void find(int x,int l,int r,int y){    ans=max(ans,t[x].p+(y-l)*t[x].q);    if(l==r){        return;    }    int mid=(l+r)/2;    if(y<=mid)find(x*2,l,mid,y);    else find(x*2+1,mid+1,r,y);}int main(){    freopen("query.in","r",stdin);    freopen("query.out","w",stdout);//  freopen("fan.in","r",stdin);//  freopen("fan.out","w",stdout);    scanf("%d%d",&n,&m);da=1000001;    fo(i,0,mxx*4-1)t[i].p=-9999999999;    fo(i,1,n){        scanf("%d%d%d%d",&x,&y,&xx,&yy);        if(x>xx)swap(x,xx),swap(y,yy);        if(x==xx&&y>yy)swap(y,yy);        x+=da,xx+=da;ha=x;        if(xx==x)kk=inf;else kk=(db)(yy-y)/(xx-x);        if(kk==inf)y=yy,kk=0;        change(1,1,2*da,x,xx,y,kk);    }    fo(i,1,m){        scanf("%d",&k);        if(k==0){            scanf("%d%d%d%d",&x,&y,&xx,&yy);            if(x>xx)swap(x,xx),swap(y,yy);            if(x==xx&&y>yy)swap(y,yy);            if(x==180){                k=k;            }            x+=da,xx+=da;ha=x;            if(xx==x)kk=inf;else kk=(db)(yy-y)/(xx-x);            if(kk==inf)y=yy,kk=0;            change(1,1,2*da,x,xx,y,kk);        }        else{            scanf("%d",&x);            x+=da;            ans=-9999999999;            find(1,1,2*da,x);            if(ans==-9999999999)ans=0;            printf("%.6lf\n",ans);        }    }}   
1 0
原创粉丝点击