bzoj 3165: [Heoi2013]Segment 动态凸壳

3165: [Heoi2013]Segment

Time Limit: 40 Sec  Memory Limit: 256 MB
Submit: 202  Solved: 89
[Submit][Status]

Description


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

Input

 
第一行一个整数n,表示共n 个操作。
接下来n行,每行第一个数为0或1。
 
若该数为 0,则后面跟着一个正整数 k,表示询问与直线 
x = ((k +lastans–1)%39989+1)相交的线段中交点(包括在端点相交的情形)最靠上的线段的编号,其中%表示取余。若某条线段为直线的一部分,则视作直线与线段交于该线段y坐标最大处。若有多条线段符合要求,输出编号最小的线段的编号。
若该数为 1,则后面跟着四个正整数 x0, y0, x 1, y 1,表示插入一条两个端点为
((x0+lastans-1)%39989+1,(y0+lastans-1)%109+1)和((x
1+lastans-1)%39989+1,(y1+lastans-1)%109+1) 的线段。
其中lastans为上一次询问的答案。初始时lastans=0。 
 
 

Output


对于每个 0操作,输出一行,包含一个正整数,表示交点最靠上的线段的编
号。若不存在与直线相交的线段,答案为0。

Sample Input

6
1 8 5 10 8
1 6 7 2 6
0 2
0 9
1 4 7 6 7
0 5

Sample Output

2
0 3

HINT



 

 

对于100%的数据,1 ≤ n ≤ 10^5 , 1 ≤  k, x0, x1 ≤ 39989, 1 ≤ y0 ≤ y1 ≤ 10^9。

 

  据说这道题可以用线段树裸搞,但是我用的是线段树维护下凸壳,考试时候如果询问坐标x值有垂直线段的话,我直接输出的垂直线段,没有考虑线段高度问题,导致wa了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#include<cmath>
using namespace std;
#define PROB "segment"
#define MAXN 60000
#define MAXT MAXN*17
#define VAL1 39989
#define VAL2 1000000000
#define lch (now<<1)
#define rch (now<<1^1)
#define INF 0x3f3f3f3f
inline int nextInt()
{
        register int x=0;
        register char ch;
        while (ch=getchar(),ch<'0' || ch>'9');
        while (x=x*10+ch-'0',ch=getchar(),ch<='9' && ch>='0');
        return x;
}
typedef double real;
const int maxval=40000;
struct point
{
        real x,y;
        point(){}
        point(real x,real y):x(x),y(y){}
        point(int x,int y):x(x),y(y){}
        void print()
        {
                printf("(%.2lf,%.2lf) ",x,y);
        }
};
struct line
{
        point ps;
        real x,y;
        real angle;
        line(){}
        line(point p1,point p2)
        {
                ps=p1;
                x=p2.x-p1.x;
                y=p2.y-p1.y;
                angle=atan(y/x);
        }
        real cross_height(real xx)
        {
                //        if (xx<ps.x || xx>ps.x+x)return -1e10;
                return ps.y + y*(xx-ps.x)/x;
        }
        point spos()
        {
                return ps;
        }
        point tpos()
        {
                return point(ps.x+x,ps.y+y);
        }
        void print()
        {
                printf("Line:");
                spos().print();
                tpos().print();
                printf("\n");
        }
}ll[MAXN];
inline real xmul(line &l1,line l2)
{
        return (l1.x*l2.y)-(l1.y*l2.x);
}
inline bool parallel(line &l1,line &l2)
{
        return xmul(l1,l2)==0;
}
inline point crossover(line &l1,line &l2)
{
        real s1=xmul(l1,line(l1.ps,l2.ps));
        real s2=-xmul(l1,line(l1.ps,l2.tpos()));
        return point(l2.ps.x+l2.x*s1/(s1+s2),
                        l2.ps.y+l2.y*s1/(s1+s2));
}
int L[MAXT],R[MAXT],S[MAXT];
int V[MAXT];
real spos[MAXT],tpos[MAXT];
int topt;
#define update(now)    S[now]=S[L[now]]+S[R[now]]+1;
#define l_rotate(now)\
        t=R[now];\
        R[now]=L[t];update(now);\
        L[t]=now;update(t);\
        now=t;
#define r_rotate(now)\
        t=L[now];\
        L[now]=R[t];update(now);\
        R[t]=now;update(t);\
        now=t;
inline void maintain(int &now)
{
        register int t;
        if (S[L[L[now]]]>S[R[now]])
        {
                r_rotate(now);
                maintain(L[now]);
                maintain(R[now]);
                maintain(now);
                return ;
        }else if (S[R[R[now]]]>S[L[now]])
        {
                l_rotate(now);
                maintain(R[now]);
                maintain(L[now]);
                maintain(now);
                return ;
        }else if (S[R[L[now]]]>S[R[now]])
        {
                l_rotate(L[now]);
                r_rotate(now);
                maintain(R[now]);
                maintain(L[now]);
                maintain(now);
                return ;
        }else if (S[L[R[now]]]>S[L[now]])
        {
                r_rotate(R[now]);
                l_rotate(now);
                maintain(R[now]);
                maintain(L[now]);
                maintain(now);
                return ;
        }
}
int Insert(int &now,int id)
{
        if (!now)
        {
                now=++topt;
                V[now]=id;
                S[now]=1;
                return now;
        }
        int ret;
        if (ll[id].angle<ll[V[now]].angle)
                ret=Insert(L[now],id);
        else
                ret=Insert(R[now],id);
        update(now);
        maintain(now);
        return ret;
}
void Delete(int &now,int aim)
{
        if (now==aim)
        {
                if (!L[now] && !R[now])
                {
                        now=0;
                        return ;
                }
                if (!L[now])
                        now=R[now];
                else if (!R[now])
                        now=L[now];
                else
                {
                        register int t;
                        r_rotate(now);
                        Delete(R[now],aim);
                }
                update(now);maintain(now);
                return ;
        }
        if (ll[V[aim]].angle < ll[V[now]].angle || 
                        (ll[V[aim]].angle==ll[V[now]].angle && aim<now))
                Delete(L[now],aim);
        else
                Delete(R[now],aim);
        update(now);
        maintain(now);
}
int Get_rank(int &now,int aim)
{
        if (now==aim)return S[L[now]]+1;
        if (ll[V[aim]].angle < ll[V[now]].angle || 
                        (ll[V[aim]].angle==ll[V[now]].angle && aim<now))
                return Get_rank(L[now],aim);
        else
                return S[L[now]]+1+Get_rank(R[now],aim);
}
int Get_kth(int &now,int rk)
{
        if (rk==S[L[now]]+1)return now;
        if (rk<S[L[now]]+1)
                return Get_kth(L[now],rk);
        else
                return Get_kth(R[now],rk-S[L[now]]-1);
}
int spos_lower_bound(int &now,int ps)
{
        if (!now)return -INF;
        if (spos[now]<ps)
        {
                int ret=spos_lower_bound(R[now],ps);
                if (ret!=-INF)return ret;
                else return now;
        }else
        {
                return spos_lower_bound(L[now],ps);
        }
}
void Scan(int now)
{
        if (!now)return;
        Scan(L[now]);
        ll[V[now]].print();
        printf("   At[%.2lf,%.2lf]\n",spos[now],tpos[now]);
        Scan(R[now]);
}

void Insert_line(int &root,int lid)
{
        register int cur=Insert(root,lid);
        register int pa,pn;
        pa=pn=-1;
        register int rk;
        point pt;
        rk=Get_rank(root,cur);
        while (true)
        {
                if (rk==1)break;
                pa=Get_kth(root,rk-1);
                if (parallel(ll[V[pa]],ll[lid]))
                {
                        if (ll[V[pa]].cross_height(1)>=ll[lid].cross_height(1))
                        {
                                Delete(root,cur);
                                return ;
                        }else
                        {
                                Delete(root,pa);
                                rk--;
                                continue;
                        }
                }    
                pt=crossover(ll[V[pa]],ll[lid]);
                tpos[pa]=pt.x;
                if (tpos[pa]<=spos[pa])
                {
                        Delete(root,pa);
                        rk--;
                }
                else
                        break;
        }
        if (rk==1)
                spos[cur]=-1e10;
        else
                spos[cur]=pt.x;
        //rk=Get_rank(root,cur);
        while (true)
        {
                if (rk==S[root])break;
                pn=Get_kth(root,rk+1);
                if (parallel(ll[V[pn]],ll[lid]))
                {
                        if (ll[V[pn]].cross_height(1)>=ll[lid].cross_height(1))
                        {
                                Delete(root,cur);
                                return ;
                        }else
                        {
                                Delete(root,pn);
                                continue;
                        }
                }    
                pt=crossover(ll[V[pn]],ll[lid]);
                spos[pn]=pt.x;
                if (tpos[pn]<=spos[pn])
                        Delete(root,pn);
                else
                        break;
        }
        if (rk==S[root])
                tpos[cur]=1e10;
        else
                tpos[cur]=pt.x;
        if (spos[cur]>=tpos[cur])
        {
                Delete(root,cur);
                if (~pa && ~pn)
                        spos[pn]=tpos[pa]=crossover(ll[V[pa]],ll[V[pn]]).x;
                else if (pa==-1)
                        tpos[pn]=1e10;
                else
                        spos[pa]=-1e10;
        }
}
pair<real,int> Search(int &root,int pos)
{
        pair<real,int> res;
        int cur=spos_lower_bound(root,pos);
        if (cur==-INF)return make_pair(-1e100,0);
        res.second=V[cur];
        res.first=ll[V[cur]].cross_height(pos);
        int rk=Get_rank(root,cur);
        if (rk==S[root])return res;
        int pa=Get_kth(root,rk+1);
        if (spos[pa]==pos)
        {
                res=min(res,make_pair(res.first,V[pa]));
        }
        return res;
}
struct sgt_node
{
        int l,r;
        int root;
}sgt[MAXT*4];
void Build_sgt(int now,int l,int r)
{
        sgt[now].l=l;sgt[now].r=r;
        if (l+1==r)return ;
        int mid=(l+r)>>1;
        Build_sgt(lch,l,mid);
        Build_sgt(rch,mid,r);
}
void Add_sgt(int now,int l,int r,int x,int y,int lid)
{
        if (l==x && r==y)
        {
                Insert_line(sgt[now].root,lid);
                return ;
        }
        int mid=(l+r)>>1;
        if (y<=mid)
                Add_sgt(lch,l,mid,x,y,lid);
        else if (mid<=x)
                Add_sgt(rch,mid,r,x,y,lid);
        else
        {
                Add_sgt(lch,l,mid,x,mid,lid);
                Add_sgt(rch,mid,r,mid,y,lid);
        }
}
pair<real,int> Query_sgt(int now,int l,int r,int pos)
{
        pair<real,int> res=Search(sgt[now].root,pos);
        res.second=-res.second;
        if (l+1==r)return res;
        int mid=(l+r)>>1;
        if (pos<mid)
                return max(res,Query_sgt(lch,l,mid,pos));
        else if (mid<pos)
                return max(res,Query_sgt(rch,mid,r,pos));
        else
                return max(res,max(Query_sgt(lch,l,mid,pos),Query_sgt(rch,mid,r,pos)));

}

pair<int,int> ignall[MAXN];
int main()
{
        freopen(PROB".in","r",stdin);
        //freopen(PROB".out","w",stdout);
        int n,m,x,y,z;
        int a,b,c,d;
        int opt;
        int lastans=0;
        m=nextInt();
    //    scanf("%d",&m);
        Build_sgt(1,1,maxval);
        n=1;
        for (int i=1;i<=m;i++)
        {
                opt=nextInt();
                //scanf("%d",&opt);
                if (opt==0)
                {
                        x=nextInt();
                        //scanf("%d\n",&x);
                        x=((x+lastans-1)%VAL1+1);
                        if (ignall[x]!=make_pair(0,0))
                        {
                                //printf("%d\n",lastans=ignall[x].second);
                                pair<real,int> res=Query_sgt(1,0,maxval,x);
                                res.second=-res.second;
                                if(ignall[x].first>res.first)
                                        printf("%d\n",lastans=ignall[x].second);
                                else
                                        printf("%d\n",lastans=res.second);
                                continue;
                        }
                        pair<real,int> res=Query_sgt(1,0,maxval,x);
                        res.second=-res.second;
                        printf("%d\n",lastans=res.second);
                }else
                {
                        a=nextInt(),b=nextInt(),c=nextInt(),d=nextInt();
                        //scanf("%d%d%d%d",&a,&b,&c,&d);
                        a=(a+lastans-1)%VAL1+1;
                        c=(c+lastans-1)%VAL1+1;
                        b=(b+lastans-1)%VAL2+1;
                        d=(d+lastans-1)%VAL2+1;
                        if (a>c)swap(a,c),swap(b,d);
                        if (a==c)
                        {
                                if (ignall[a].first<max(b,d))
                                        ignall[a]=make_pair(max(b,d),n);
                                n++;
                                continue;
                        }
                        ll[n++]=line(point(a,b),point(c,d));
                        Add_sgt(1,0,maxval,a,c,n-1);
                }
        }
}

 

转载于:https://www.cnblogs.com/mhy12345/p/4313596.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值