Description
要求在平面直角坐标系下维护两个操作:
在平面上加入一条线段。记第 i条被插入的线段标号为 i。
给定一个数 k,询问与直线 x = k相交的线段中,交点最靠上的线段的编号。
对于 100% 的数据, 1 ≤ n ≤ 10^5, 1 ≤ k, x0, x1 ≤ 39989, 1 ≤ y0 ≤ y1 ≤ 10^9。
线段树
Get到线段树新姿势,听说叫超哥线段树(:з)∠)
线段一多就特别乱,所以对于线段树中每个线段,只保存一条优势直线
一条直线如何成为线段的优势直线?如果原来线段没有优势直线,那么直接插入就好
否则需要拿当前直线A与原有直线B进行比对,看看在当前线段中,哪条线段是大部分位置更高的那一条
//比对容易用几何方法完成,平行于y轴可以特判,不再赘述
假设A被保存,B被A替换,不妨只讨论B在[l,x] (x<=mid)中比A高
那么B存在的意义只有线段[l,mid],递归处理
其它讨论类似
考虑查询直线x=i,在线段树的线段查找到i位置的过程中,将所有出现的优势线段该位置高度取max即可
线段树真的有无限的可能,是一个功能无比强大的简洁数据结构,技巧性的东西非常多
复杂度nlog^2
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define efo(i,v) for(int i=last[v];i;i=next[i])
using namespace std;
typedef double db;
const int X=40000,N=100005;
const db eps=1e-12;
int ans,lstans,x0,y0,x1,y1,tr[X*4];
db mx;
struct line
{
int x0,y0,x1,y1;
}a[N];
void turnx(int &x){x=((x+lstans-1)%39989+1);}
void turny(int &y){y=((y+lstans-1)%int(1e9)+1);}
db high(line a,int x)
{
if(a.x0==a.x1) return a.y0>a.y1?a.y0:a.y1;
db k=1.0*(a.y1-a.y0)/(a.x1-a.x0);
return k*(x-a.x0)+a.y0;
}
db slope(line a)
{
if(a.x0==a.x1) return 1e15;
return 1.0*(a.y1-a.y0)/(a.x1-a.x0);
}
void getcross(line a,line b,db &x,db &y)
{
if(a.x0==a.x1 && a.x0==b.x0 && b.x0==b.x1) x=y=0;
else
if(a.x0==a.x1) x=a.x0,y=high(b,x);
else
if(b.x0==b.x1) x=b.x0,y=high(a,x);
else
{
db ka=1.0*(a.y1-a.y0)/(a.x1-a.x0),kb=1.0*(b.y1-b.y0)/(b.x1-b.x0);
if(ka==kb) {x=-1;y=0;return;}
x=1.0*(ka*a.x0-kb*b.x0+b.y0-a.y0)/(ka-kb);
y=a.y0+(x-a.x0)*ka;
}
}
void change(int v,int l,int r,int id)
{
int mid=(l+r)>>1;
if(a[id].x0<=l && r<=a[id].x1)
{
if(!tr[v])
{
tr[v]=id;
return;
}
db xx,yy;
getcross(a[tr[v]],a[id],xx,yy);
bool p=slope(a[id])<slope(a[tr[v]]);
if(xx<l-eps || xx>r+eps || l==r)
{
db h1=high(a[id],l),h2=high(a[tr[v]],l);
if(h1>h2 || h1==h2 && id<tr[v]) tr[v]=id;
return;
}
if(p)
{
if(xx>mid)
{
change(v+v+1,mid+1,r,tr[v]);
tr[v]=id;
}
else change(v+v,l,mid,id);
}
else
{
if(xx<=mid)
{
change(v+v,l,mid,tr[v]);
tr[v]=id;
}
else change(v+v+1,mid+1,r,id);
}
return;
}
if(a[id].x1<=mid) change(v+v,l,mid,id);
else
if(a[id].x0>mid) change(v+v+1,mid+1,r,id);
else
change(v+v,l,mid,id),change(v+v+1,mid+1,r,id);
}
void query(int v,int l,int r,int x)
{
db h=high(a[tr[v]],x);
if(h>mx || h==mx && tr[v]<ans) mx=h,ans=tr[v];
if(l==r) return;
int mid=(l+r)>>1;
if(x<=mid) query(v+v,l,mid,x);
else query(v+v+1,mid+1,r,x);
}
int main()
{
int m,tp,num=0;
scanf("%d",&m);
fo(i,1,m)
{
scanf("%d",&tp);
if(tp==0)
{
scanf("%d",&x0);turnx(x0);
ans=mx=0;
query(1,1,X,x0);
printf("%d\n",ans);
lstans=ans;
}
else
{
num++;
scanf("%d %d %d %d",&a[num].x0,&a[num].y0,&a[num].x1,&a[num].y1);
turnx(a[num].x0);turny(a[num].y0);turnx(a[num].x1);turny(a[num].y1);
if(a[num].x0>a[num].x1) swap(a[num].x0,a[num].x1),swap(a[num].y0,a[num].y1);
change(1,1,X,num);
}
}
return 0;
}