题意:
要求在平面直角坐标系下维护两个操作:
- 在平面上加入一条线段。记第 i 条被插入的线段的标号为 i
- 给定一个数 k,询问与直线 x = k 相交的线段中,交点最靠上的线段的编号。
思路:李超线段树
原理:线段树的节点维护的是该节点的区间中点的横坐标处y值最大的线段的标号。不需要pushup和pushdown,查询时整条链的节点都需要考虑。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100005;
const double eps = 1e-6;
int sgn( double x ){
if( x > eps ) return 1;
else if( x < -eps ) return -1;
else return 0;
}
struct Line{
int l,r,id; // 线段的下标需要从1开始
double yl,yr,k;
Line(){}
Line( int _l,int _r,int _yl,int _yr,int _id ){
l = _l;r = _r;yl = _yl;yr = _yr;id = _id;k = ( l-r ) ? (yl-yr)/(l-r):0;
if( l == r ) yl = yr = max( yl,yr ); //( 斜率为无穷大需要特判 )
}
double operator()( int x ){ return l == r?yl:yl + k*( x-l ); }
}a[maxn];
int tree[4*maxn];
bool cmp( int x,int y,int i ){
return a[x](i) > a[y](i) ;
}
int tot = 1,ls[4*maxn],rs[4*maxn];
int query( int p,int l,int r,int x ){
if( l == r ) {
return tree[x];
}
int tmp=0;
int mid = l+r>>1;
if( ls[x] &&p <= mid ) tmp = query( p,l,mid,ls[x] );
else if( rs[x] &&p > mid ) tmp = query( p,mid+1,r,rs[x] );
if( !tmp ) return tree[x];
else if( !tree[x] ){
return tmp;
}else if( tmp && tree[x] ){
return cmp( tmp,tree[x],p ) ? tmp : tree[x];
}else return 0;
}
void update( int k,int l,int r,int x ){
if( a[k].l > r || a[k].r < l ) return;
if( l == r ){
if( !tree[x] ) {
tree[x] = k;
}else if( cmp( k,tree[x],l ) ) swap( tree[x],k );
return;
}
int mid = l+r>>1;
if( a[k].l <= l && a[k].r >= r ){
if( !tree[x] ) {
tree[x] = k;
return;
}
else {
if( cmp( k,tree[x],mid ) ) swap( tree[x],k );
int l1 = a[tree[x]](l),l2 = a[k](l),r1 = a[tree[x]](r),r2 = a[k](r);
if( sgn( r1-r2 ) >= 0 && sgn( l1-l2 ) >= 0 ){
return;
}
if( sgn(l2-l1) >= 0 ){
if(!ls[x])ls[x] = ++tot;
update( k,l,mid,ls[x] );
}
if( sgn(r2-r1) >= 0 ) {
if(!rs[x])rs[x] = ++tot;
update( k,mid+1,r,rs[x] );
}
}
}else{
if(!ls[x] ) ls[x] =++tot;update( k,l,mid,ls[x] );
if(!rs[x] ) rs[x] =++tot;update( k,mid+1,r,rs[x] );
}
}
int main(){
int n,op,x0,y0,x1,y1,x;
scanf("%d",&n);
int lastans = 0,num = 0;
for( int i = 1;i <= n;i++ ){
scanf("%d",&op);
if( op ){
scanf("%d%d%d%d",&x0,&y0,&x1,&y1);
x0 = (x0+lastans-1)%39989+1,y0 = (y0+lastans-1)%1000000000+1;
x1 = (x1+lastans-1)%39989+1,y1 = (y1+lastans-1)%1000000000+1;
if( x0 > x1 ){
swap( x0,x1 );swap( y0,y1 );
}
a[++num] = Line( x0,x1,y0,y1,num );
update( num ,1,39989,1 );
}else{
scanf("%d",&x);
x = ((x + lastans - 1)%39989+1);
lastans = query( x,1,39989,1 );
printf("%d\n",lastans);
}
}
return 0;
}