首页 > 其他 > 详细

[bzoj3165] [HEOI2013]Segment

时间:2019-01-10 19:20:43      阅读:33      评论:0      收藏:0      [点我收藏+]

标签:每次   class   turn   一个   last   -o   ons   整数   modify   

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 

Solution

李超线段树。

线段树每个区间记录一条最优线段。

对于一条线段,以及一条新加的线段,分类讨论:

  • 若新线段和旧线段没有交点,更新之后直接退出就好了。
  • 否则考虑交点和\(mid\)的位置关系,一边直接覆盖,另一边递归处理。

对于每次操作,一共会拆成\(O(\log n)\)个区间,每个区间花费\(O(\log n)\)的代价更新,总复杂度\(O(m\log^2n)\)

#include<bits/stdc++.h>
using namespace std;
 
void read(int &x) {
    x=0;int f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
 
void print(int x) {
    if(x<0) putchar('-'),x=-x;
    if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}

const int maxn = 5e5+10;
const int N = 4e4;

struct data {
    int x,y,xx,yy,id;
    double k,b;    
    double calc(int a) {return k*a+b;}
    void lm(int a) {y=calc(a),x=a;}
    void rm(int a) {yy=calc(a),xx=a;}
};

int judge(data a,data b,int x) {
    if(!a.id) return 1;
    return a.calc(x)==b.calc(x)?a.id>b.id:a.calc(x)<b.calc(x);
}

int cnt;

#define ls p<<1
#define rs p<<1|1
#define mid ((l+r)>>1)

struct Segment_Tree {
    data t[maxn<<2];
    void update(int p,int l,int r,data s) {
        if(s.x<l) s.lm(l);
        if(s.xx>r) s.rm(r);
        if(judge(t[p],s,mid)) swap(s,t[p]);
        if(l==r) return ;
        if(max(s.y,s.yy)<=min(t[p].y,t[p].yy)) return ;
        if(s.k>t[p].k) update(rs,mid+1,r,s);
        else update(ls,l,mid,s);
    }
    void modify(int p,int l,int r,data s) {
        if(s.x<l) s.lm(l);
        if(s.xx>r) s.rm(r);
        if(s.x==l&&s.xx==r) return update(p,l,r,s),void();
        if(s.x<=mid) modify(ls,l,mid,s);
        if(s.xx>mid) modify(rs,mid+1,r,s);
    }
    data query(int p,int l,int r,int x) {
        if(l==r) return t[p];
        data ans=t[p],res;
        if(x<=mid) res=query(ls,l,mid,x);
        else res=query(rs,mid+1,r,x);
        if(judge(ans,res,x)) ans=res;
        return ans;
    }
}SGT;

int main() {
    int t;read(t);
    int lastans=0,id=0;
    data s;
    while(t--) {
        int op,x,y,xx,yy;read(op);
        if(op==1) {
            read(x),read(y),read(xx),read(yy);
            x=(x+lastans-1)%39989+1;
            y=(y+lastans-1)%1000000000+1;
            xx=(xx+lastans-1)%39989+1;
            yy=(yy+lastans-1)%1000000000+1;
            if(x>xx) swap(x,xx),swap(y,yy);
            if(x==xx) {
                y=max(y,yy);
                s=(data){x,y,xx,y,++id,0,1.0*y};
            } else {
                double k=(double)(y-yy)/(1.0*(x-xx));
                s=(data){x,y,xx,yy,++id,k,1.0*y-1.0*x*k};
            }
            SGT.modify(1,1,N,s);
        } else {
            read(x);x=(x+lastans-1)%39989+1;
            write(lastans=SGT.query(1,1,N,x).id);
        }
    }
    return 0;
}

[bzoj3165] [HEOI2013]Segment

标签:每次   class   turn   一个   last   -o   ons   整数   modify   

原文:https://www.cnblogs.com/hbyer/p/10251789.html

(0)
(0)
   
举报
评论 一句话评论(0
0条  
登录后才能评论!
© 2014 designnerd.net 版权所有 鲁ICP备09046678号-4
打开技术之扣,分享程序人生!
             

鲁公网安备 37021202000002号