zoukankan      html  css  js  c++  java
  • BZOJ3165[Heoi2013]Segment——李超线段树

    题目描述

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

    输入

    第一行一个整数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。 

    输出

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

    样例输入

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

    样例输出

    2
    0 3

    提示

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

    模板题,线段树上每个点存覆盖整个区间的最优线段。对于每条输入线段如果完全覆盖当前区间就进行以下判断,否则看它在左右子区间是否有覆盖的部分递归下去。对于完全覆盖当前区间分四种情况讨论:

    1、当前区间无线段覆盖,直接将新线段存起来

    2、当前区间存的线段完全覆盖新线段,直接返回

    3、新线段完全覆盖当前区间存的线段,将新线段存起来

    4、当前区间存的线段和新线段相交,将区间中点处更高的存为当前区间的线段,并将另一条线段向它左右两端较高的那端的子区间递归下去

    查询时只要将查询路径上所有线段取最高的那个即可。

    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<cmath>
    #include<cstdio>
    #include<vector>
    #include<bitset>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define ll long long 
    #define eps 1e-8
    using namespace std;
    int num[200010];
    double k[100010];
    double b[100010];
    int n;
    int opt;
    int cnt;
    int ans;
    int X0,Y0,X1,Y1;
    bool cmp(double x)
    {
    	return fabs(x)<=eps;
    }
    double f(int id,int x)
    {
    	return k[id]*x+b[id];
    }
    bool judge(int idx,int idy,int x)
    {
    	double fx=f(idx,x);
    	double fy=f(idy,x);
    	return cmp(fx-fy)?idx<idy:fx<fy;
    }
    void change(int rt,int l,int r,int L,int R,int id)
    {
    	int mid=(l+r)>>1;
    	if(L<=l&&r<=R)
    	{
    		if(judge(id,num[rt],l)&&judge(id,num[rt],r))
    		{
    			return ;
    		}
    		if(judge(num[rt],id,l)&&judge(num[rt],id,r))
    		{
    			num[rt]=id;
    			return ;
    		}
    		if(judge(num[rt],id,mid))
    		{
    			swap(num[rt],id);
    		}
    		if(judge(num[rt],id,l))
    		{
    			change(rt<<1,l,mid,L,R,id);
    		}
    		else
    		{
    			change(rt<<1|1,mid+1,r,L,R,id);
    		}
    		return ;
    	}
    	if(L<=mid)
    	{
    		change(rt<<1,l,mid,L,R,id);
    	}
    	if(R>mid)
    	{
    		change(rt<<1|1,mid+1,r,L,R,id);
    	}
    }
    int query(int rt,int l,int r,int x)
    {
    	if(l==r)
    	{
    		return num[rt];
    	}
    	int mid=(l+r)>>1;
    	int res=x<=mid?query(rt<<1,l,mid,x):query(rt<<1|1,mid+1,r,x);
    	if(judge(res,num[rt],x))
    	{
    		res=num[rt];
    	}
    	return res;
    }
    int main()
    {
    	ans=-1;
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%d",&opt);
    		if(opt)
    		{
    			scanf("%d%d%d%d",&X0,&Y0,&X1,&Y1);
    			cnt++;
    			X0=(X0+ans+39989)%39989+1,Y0=(1ll*Y0+ans+1000000000)%1000000000+1;
                X1=(X1+ans+39989)%39989+1,Y1=(1ll*Y1+ans+1000000000)%1000000000+1;
                if(X1<X0)
                {
                	swap(X1,X0);
                	swap(Y1,Y0);
                }
                if(X1==X0)
                {
                	k[cnt]=0;
                	b[cnt]=max(Y0,Y1);
                }
                else
                {
                	k[cnt]=(double)(Y1-Y0)/(X1-X0);
                	b[cnt]=Y1-k[cnt]*X1;
                }
                change(1,1,40000,X0,X1,cnt);
    		}
    		else
    		{
    			scanf("%d",&X0);
    			X0=(X0+ans+39989)%39989+1;
    			ans=query(1,1,40000,X0);
    			printf("%d
    ",ans);
    			ans--;
    		}
    	}
    }
  • 相关阅读:
    BZOJ1556 墓地秘密
    [NOI2006]网络收费
    UVA11401 Triangle Counting
    UVA11538 Chess Queen
    BZOJ2560 串珠子
    BZOJ4057 [Cerc2012]Kingdoms
    [HNOI2012] 集合选数
    [Haoi2016]字符合并
    [Snoi2013]Quare
    洛谷平衡树模板总结
  • 原文地址:https://www.cnblogs.com/Khada-Jhin/p/10381272.html
Copyright © 2011-2022 走看看