BZOJ3165: [Heoi2013]Segment(线段树)

来源:互联网 发布:convertfrom json 编辑:程序博客网 时间:2024/05/21 22:48

传送门

要求在平面直角坐标系下维护两个操作:
1.在平面上加入一条线段。记第i条被插入的线段的标号为i。
2.给定一个数k,询问与直线 x = k相交的线段中,交点最靠上的线段的编号。

题解:
好题啊。。

可以假设目前每个区间只有一条线段覆盖(初始化为0),考虑新加入一条边的影响:
如果这条边在原边之上或者之下,那么直接保留较上面的边就行了。

如果有交点,那么一定有一条线段覆盖了区间的一半(交点的左边或者后边),那么这个区间保留这条线段,将另一条影响较小的线段下传到子树处理子问题就好了。每条线段减小一半,那么只会影响到logn个区间,一次至多加入logn条线段,总的复杂度为O(nlog2n)
(注意处理线段退化为点的边界情况)
查询时查找根到节点的最大值即可。

Code:

#include<bits/stdc++.h>using namespace std;inline int read(){    char ch=getchar();int i=0,f=1;    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}    while(isdigit(ch)){i=(i<<1)+(i<<3)+ch-'0';ch=getchar();}    return i*f;} inline void W(int x){    static int buf[50];    if(!x){putchar('0');return;}    while(x)buf[++buf[0]]=x%10,x/=10;    while(buf[0])putchar(buf[buf[0]--]+'0');}const int Maxn=2e5+50,Rlim=39989;const int LIM=1e9;const double eps=1e-9;inline int sgn(double x){return (x>eps)-(x<-eps);}double ly[Maxn],ry[Maxn];int n,p,id,ind[Maxn],L,R,yc0,yc1,cnt;double mx;inline double calc(int l,double lc,int r,double rc,int pos){    if(l==r&&l==pos)return lc;    double sp=(rc-lc)/(r-l);    return (double)lc+sp*(pos-l);}inline double calc2(int l,int r,double lc1,double rc1,double lc2,double rc2){    double sp1=(rc1-lc1)/(r-l),sp2=(rc2-lc2)/(r-l);    return (lc2-lc1)/(sp1-sp2)+l;}inline void upt(int k,int l,int r,double lc,double rc,int ii){    if(!ind[k]){ly[k]=lc,ry[k]=rc;ind[k]=ii;return;}    if(l==r){        if(sgn(ly[k]-lc)<0)ly[k]=(ry[k]=lc),ind[k]=ii;        return;    }    int t1=sgn(ly[k]-lc),t2=sgn(ry[k]-rc);    if((t1>=0&&t2>=0&&ind[k]<ii)||(t1>0&&t2>0))return;    if((t1<=0&&t2<=0&&ind[k]>ii)||(t1<0&&t2<0)){ly[k]=lc,ry[k]=rc;ind[k]=ii;return;}    double pos=calc2(l,r,lc,rc,ly[k],ry[k]);    int mid=(l+r)>>1;    if(sgn(pos-mid)<=0){        if(sgn(ly[k]-lc)>=0&&sgn(ry[k]-rc)<=0){            double v=calc(l,ly[k],r,ry[k],mid),v2=ly[k];            ly[k]=lc,ry[k]=rc;upt(k<<1,l,mid,v2,v,ind[k]);ind[k]=ii;        }else{            double v=calc(l,lc,r,rc,mid),v2=lc;            upt(k<<1,l,mid,v2,v,ii);        }    }else{        if(sgn(ly[k]-lc<=0)&&sgn(ry[k]-rc)>=0){            double v=calc(l,ly[k],r,ry[k],mid+1),v2=ry[k];            ly[k]=lc,ry[k]=rc;upt(k<<1|1,mid+1,r,v,v2,ind[k]);ind[k]=ii;        }else{            double v=calc(l,lc,r,rc,mid+1),v2=rc;            upt(k<<1|1,mid+1,r,v,v2,ii);        }    }}inline void modify(int k,int l,int r,int ii){    if(L<=l&&r<=R){upt(k,l,r,calc(L,yc0,R,yc1,l),calc(L,yc0,R,yc1,r),ii);return;}    int mid=(l+r)>>1;    if(R<=mid)modify(k<<1,l,mid,ii);    else if(L>mid)modify(k<<1|1,mid+1,r,ii);    else modify(k<<1,l,mid,ii),modify(k<<1|1,mid+1,r,ii);}inline int query(int k,int l,int r,int pos){    if(l==r){        if(sgn(ly[k]-mx)>0||(sgn(ly[k]-mx)>=0&&ind[k]<id))mx=ly[k],id=ind[k];        return id;    }    double y=calc(l,ly[k],r,ry[k],pos);    if(sgn(y-mx)>0||(sgn(y-mx)>=0&&ind[k]<id))mx=y,id=ind[k];    int mid=(l+r)>>1;    return (pos<=mid)?(query(k<<1,l,mid,pos)):(query(k<<1|1,mid+1,r,pos));}int main(){    n=read();    for(int i=1;i<=n;i++){        int op=read();        if(op==1){            L=(read()+p-1)%Rlim+1,yc0=(read()+p-1)%LIM+1;            R=(read()+p-1)%Rlim+1,yc1=(read()+p-1)%LIM+1;            if(L>R)swap(L,R),swap(yc0,yc1);            if(L==R)yc0=(yc1=max(yc0,yc1));            ++cnt;modify(1,1,Rlim,cnt);        }else (mx=0,id=0,p=query(1,1,Rlim,(read()+p-1)%Rlim+1),W(p),putchar('\n'));    }}
原创粉丝点击