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),(y0+lastans−1) 和 ((x1+lastans−1),(y1+lastans−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
Data
对于100%的数据,1≤n≤105,1≤k,x0,x1≤39989,1≤y0≤y1≤109。
I think
以x轴横轴建树,新加入一条线段a时,若原区间未被任何线段覆盖,则直接将线段保存在区间。若原区间已保存有线段b,则比较线段a b在该区间覆盖的大小,将覆盖较大的线段保留,另一条向子区间递归下去。
存线段也可以用结构体存斜率和截距,计算与判断会更好写。
这道题调了很久的bug是处理线段与询问点所在直线完全重合的情况,存在x1==x2的情况时若不加判断,那么函数get返回-nan,判断顺序错了就会WA。在modify中对重合情况的判断,条件不能是ll==rr,因为在递归过程中ll rr 有可能被改为与区间一致,实际却并不是重合的情况,因此条件是 x1[t]==x2[t]。
调试的手速很重要。任何一个细节,无论顺序,数组大小,无意重名的变量……在看似调不出来的情况下要勇于尝试,用心思考。
Code
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;
const int mod = 39989;
const int inf = 1e9;
const int sm = 1e5+10;
const int sn = 160000;
const double eps = 1e-10;
int n,s,pre;
int x1[sm],x2[sm],yy1[sm],y2[sm],p[sn];
void Swap(int &x,int &y) { int t=x;x=y;y=t; }
double get(int t,int x) {
if(x2[t]-x1[t]==0)return y2[t];
return (1.0*(x-x1[t])*y2[t]+1.0*yy1[t]*(x2[t]-x))/(x2[t]-x1[t]);
}
int dcmp(double x,double y) {
return fabs(x-y)<eps?0:(x>y)?1:-1;
}
int Max(int x,int y) { return x>y?x:y; }
char ch;
void read(int &x) {
x=0,ch=getchar();
while(ch>'9'||ch<'0') ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
}
void modify(int i,int l,int r,int ll,int rr,int t) {
int m=(l+r)>>1;
if(ll<=l&&r<=rr) {
if(x1[t]==x2[t]){
if(!p[i])p[i]=t;
else if(Max(yy1[t],y2[t])>Max(yy1[p[i]],y2[p[i]]))
p[i]=t;
}
else {
if(!p[i]) p[i]=t;
else {
int ja,jb,jm;
ja=dcmp(get(t,l),get(p[i],l))>0;
jb=dcmp(get(t,r),get(p[i],r))>0;
if(ja&jb) p[i]=t;
else if(ja+jb) {
jm=dcmp(get(t,m),get(p[i],m))>0;
if(ja&jm) modify(i<<1|1,m+1,r,m+1,r,p[i]),p[i]=t;
else if(jb&jm) modify(i<<1,l,m,l,m,p[i]),p[i]=t;
else if(ja) modify(i<<1,l,m,l,m,t);
else modify(i<<1|1,m+1,r,m+1,r,t);
}
}
}
return ;
}
if(ll<=m)modify(i<<1,l,m,ll,rr,t);
if(rr> m)modify(i<<1|1,m+1,r,ll,rr,t);
}
int chk(int a,int b,int x) {
if(!(a*b))return a+b;
int ys=dcmp(get(a,x),get(b,x));
return !ys?(a<b?a:b):(ys==1?a:b);
}
int query(int i,int l,int r,int x) {
if(l==r) return p[i];
int m=(l+r)>>1;
if(x<=m) return chk(p[i],query(i<<1,l,m,x),x);
else return chk(p[i],query(i<<1|1,m+1,r,x),x);
}
int main() {
freopen("segment.in","r",stdin);
freopen("segment.out","w",stdout);
read(n);
for(int i=1,ind;i<=n;++i) {
read(ind);
if(ind) {
read(x1[++s]),read(yy1[s]),read(x2[s]),read(y2[s]);
x1[s]=(x1[s]+pre-1)%mod+1,x2[s]=(x2[s]+pre-1)%mod+1;
yy1[s]=(yy1[s]+pre-1)%inf+1,y2[s]=(y2[s]+pre-1)%inf+1;
if(x1[s]>x2[s]) Swap(x1[s],x2[s]),Swap(yy1[s],y2[s]);
modify(1,1,mod,x1[s],x2[s],s);
}
else {
read(ind);ind=(ind+pre-1)%mod+1;
printf("%d\n",pre=query(1,1,mod,ind));
}
}
return 0;
}