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)和((x1+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
HINT
对于100%的数据,1 ≤ n ≤ 10^5 , 1 ≤ k, x0, x1 ≤ 39989, 1 ≤ y0 ≤ y1 ≤ 10^9。
解题思路:
线段树的神奇应用。
由于坐标都是正整数且x范围很小,所以考虑对x坐标建一棵线段树。
比较直接的想法是每个节点维护覆盖这个区间最上面的折线,但显然会被卡。
考虑每个节点只记覆盖这个区间的一条线段。
插入一条线段,一直递归线段数到覆盖了该区间。
如果当前区间没有被线段覆盖,那么就直接更新。
如果当前区间被线段覆盖了,如果两个线段没有交点,那么取高的那一个,否则取形成折线中x范围长的那个,那么拿短的线段去更新儿子,这样可以保证只会更新线段树的一条路径。
查询:
从根节点开始一直查询到底,中间每一条线段都要计算。
因为线段会被拆成 O(logn) O ( l o g n ) 个区间,每个区间又要向下延伸 O(logn) O ( l o g n ) 步,所以复杂度是 O(nlog2n) O ( n l o g 2 n ) 的。
#include<bits/stdc++.h>
using namespace std;
int getint()
{
int i=0,f=1;char c;
for(c=getchar();(c!='-')&&(c<'0'||c>'9');c=getchar());
if(c=='-')f=-1,c=getchar();
for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
const int N=40000;
int m,n=40000,cnt,ans;
int x[N<<2],y[N<<2],id[N<<2];
double K[N<<2],ansy;
double Y(int x0,int y0,double k,int qx){return (double)y0+k*(qx-x0);}
void modify(int k,int l,int r,int ql,int qr,int qx,int qy,double qK,int i)
{
int mid=l+r>>1;
if(l==ql&&r==qr)
{
if(!id[k]){x[k]=qx,y[k]=qy,K[k]=qK,id[k]=i;return;}
double ly1=Y(x[k],y[k],K[k],l),ry1=Y(x[k],y[k],K[k],r);
double ly2=Y(qx,qy,qK,l),ry2=Y(qx,qy,qK,r);
if(ly1>=ly2&&ry1>=ry2)return;
if(ly1<=ly2&&ry1<=ry2){x[k]=qx,y[k]=qy,K[k]=qK,id[k]=i;return;}
double x0=((double)y[k]-(double)qy+qK*qx-K[k]*x[k])/(qK-K[k]);
if(ly1<ly2)
if(x0<=mid)modify(k<<1,l,mid,l,mid,qx,qy,qK,i);
else
{
modify(k<<1|1,mid+1,r,mid+1,r,x[k],y[k],K[k],id[k]);
x[k]=qx,y[k]=qy,K[k]=qK,id[k]=i;
}
else
if(x0<=mid)
{
modify(k<<1,l,mid,l,mid,x[k],y[k],K[k],id[k]);
x[k]=qx,y[k]=qy,K[k]=qK,id[k]=i;
}
else modify(k<<1|1,mid+1,r,mid+1,r,qx,qy,qK,i);
}
if(qr<=mid)modify(k<<1,l,mid,ql,qr,qx,qy,qK,i);
else if(ql>mid)modify(k<<1|1,mid+1,r,ql,qr,qx,qy,qK,i);
else modify(k<<1,l,mid,ql,mid,qx,qy,qK,i),modify(k<<1|1,mid+1,r,mid+1,qr,qx,qy,qK,i);
}
void query(int k,int l,int r,int qx)
{
double tmpy=Y(x[k],y[k],K[k],qx);
if(tmpy>ansy||tmpy==ansy&&id[k]<ans)ansy=tmpy,ans=id[k];
if(l==r)return;
int mid=l+r>>1;
if(qx<=mid)query(k<<1,l,mid,qx);
else query(k<<1|1,mid+1,r,qx);
}
int main()
{
int op,X1,X2,Y1,Y2;double qK;
m=getint();
while(m--)
{
op=getint();
if(!op)
{
X1=(getint()+ans-1)%39989+1;
ans=0,ansy=0;
query(1,1,n,X1);
printf("%d\n",ans);
}
else
{
X1=(getint()+ans-1)%39989+1;
Y1=(getint()+ans-1)%1000000000+1;
X2=(getint()+ans-1)%39989+1;
Y2=(getint()+ans-1)%1000000000+1;
if(X1>X2)swap(X1,X2),swap(Y1,Y2);
if(X1==X2)Y1=max(Y1,Y2),qK=0;
else qK=(Y2-Y1)*1.0/(X2-X1);
modify(1,1,n,X1,X2,X1,Y1,qK,++cnt);
}
}
return 0;
}