BZOJ3165 Heoi2013 Segment

来源:互联网 发布:mac pro使用攻略 编辑:程序博客网 时间:2024/05/21 17:49

3165: [Heoi2013]Segment
Time Limit: 40 Sec Memory Limit: 256 MB
Submit: 616 Solved: 253
[Submit][Status][Discuss]
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)%10^9+1)和((x
1+lastans-1)%39989+1,(y1+lastans-1)%10^9+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。

//y1 居然是关键字 //超哥线段树 余生不想再碰第二遍#include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<algorithm>#include<iostream>#define maxn 100010#define mod 39989#define mody 1000000000#define eps 1e-10using namespace std;struct yts { int l,r,flag; }tre[4*maxn];struct Line{    int l,r;    double k,b;    double f(int x) {        return k*x+b;    }}st[maxn];int wi[maxn];double wy[maxn];int n,m,tot,ans,ansi,T;double ansy;Line calc(int x2,int y2,int x3,int y3) {    Line ans;    ans.l=min(x2,x3);ans.r=max(x2,x3);    if (x2!=x3) ans.k=(y2-y3)/(double)(x2-x3),ans.b=y2-x2*ans.k;    else ans.k=0.0,ans.b=max(y2,y3);    return ans;}int cross(int u,int j){return floor((st[u].b-st[j].b)/(st[j].k-st[u].k));}int sg(double x){return (x>-eps)-(x<eps);}void UpDate(int u,int x){    double y=st[x].f(u);    bool s=sg(y-wy[u]);    if(!wi[u] || (s>0 || (s==0 && x<wi[u]))){wy[u]=y;wi[u]=x;}}void Build(int u,int l,int r){    tre[u].l=l;tre[u].r=r;tre[u].flag=0;    if (l==r) return;    int Mid=(l+r)/2;    Build(u*2,l,Mid);Build(u*2+1,Mid+1,r);}void Modify(int u,int x){    if(st[x].l<=tre[u].l&&tre[u].r<=st[x].r){        if(!tre[u].flag){ tre[u].flag=x;return; }        int Mid=(tre[u].l+tre[u].r)/2;        bool lu=sg((st[x].f(tre[u].l)-st[tre[u].flag].f(tre[u].l)))>0;        bool ru=sg((st[x].f(tre[u].r)-st[tre[u].flag].f(tre[u].r)))>0;        if(lu&&ru) tre[u].flag=x;        else if (lu || ru){            int tt=cross(x,tre[u].flag);            if(tt<=Mid && lu) Modify(u*2,x);            if(tt<=Mid && ru) Modify(u*2,tre[u].flag),tre[u].flag=x;            if(tt>Mid && ru) Modify(u*2+1,x);            if(tt>Mid && lu) Modify(u*2+1,tre[u].flag),tre[u].flag=x;        } else UpDate(tre[u].l,x),UpDate(tre[u].r,x);        return;    }    int Mid=(tre[u].l+tre[u].r)/2;    if (st[x].l<=Mid) Modify(u*2,x);    if (Mid<st[x].r) Modify(u*2+1,x);}void query(int u,int x){    if(tre[u].flag){        double y=st[tre[u].flag].f(x);        int s=sg(y-ansy);        if(s>0 || (s==0 && tre[u].flag<ansi)){            ansy=y;ansi=tre[u].flag;        }    }    if(tre[u].l==tre[u].r) return;    int Mid=(tre[u].l+tre[u].r)/2;    if(x<=Mid) query(u*2,x);    if(Mid<x) query(u*2+1,x);}int main(){    scanf("%d",&T);    Build(1,1,mod);    while(T--){        int op,x2,y2,x3,y3;        scanf("%d",&op);        if(op){            scanf("%d%d%d%d",&x2,&y2,&x3,&y3);            x2=(x2+ans-1)%mod+1;y2=(y2+ans-1)%mody+1;            x3=(x3+ans-1)%mod+1;y3=(y3+ans-1)%mody+1;            st[++tot]=calc(x2,y2,x3,y3);            Modify(1,tot);        } else{            scanf("%d",&x2);            x2=(x2+ans-1)%mod+1;            ansi=0;ansy=-1.0;query(1,x2);            int s=sg(wy[x2]-ansy);            if (s>0 || (s==0 && wi[x2]<ansi)) ansi=wi[x2];            ans=ansi;            printf("%d\n",ans);        }    }    return 0;}