zoukankan      html  css  js  c++  java
  • [bzoj3165] [HEOI2013]Segment

    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(mlog^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('
    ');}
    
    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;
    }
    
  • 相关阅读:
    idea破解
    metasploit常用命令(持續更新...)
    metasploit魔鬼训练营_XSS
    渗透测试流程
    中国电信猫后接路由器具体设置
    python首次尝试——hello world
    【阿圆总结】关于平时阅读的推荐
    【转载】curl 模拟 GETPOST 请求,curl查看响应头 以及 curl post 上传文件
    【转载】用实例给新手讲解RSA加密算法
    【翻译】Open ID Connect---OIDC 是什么东西?
  • 原文地址:https://www.cnblogs.com/hbyer/p/10251789.html
Copyright © 2011-2022 走看看