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\n",ans);
			ans--;
		}
	}
}
posted @ 2019-02-14 23:22  The_Virtuoso  阅读(179)  评论(0编辑  收藏  举报