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,每个节点记录把当前区间完全覆盖并且最靠上的线段,如果有两条线段相交就随便选一条,另一条看成两条线段向下递归,注意各种细节,但是貌似这题不卡精度。每次查询取每个经过区间的最优解,因为对于一个点,每个包含这个点的区间都有可能是最优解。复杂度我并不会证...貌似是O(nlog^2n)。
下面是代码:
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<iostream> 5 #include<cmath> 6 using namespace std; 7 int st,ed,cnt,ans,imod=39989; 8 double mx,hi[40000]; 9 struct node{ 10 int x,y,xx,yy; 11 double k,b; 12 void read(){ 13 scanf("%d%d%d%d",&x,&y,&xx,&yy); 14 x=(x+ans-1)%imod+1; 15 xx=(xx+ans-1)%imod+1; 16 y=(y+ans-1)%1000000000+1; 17 yy=(yy+ans-1)%1000000000+1; 18 if(x>xx) swap(x,xx),swap(y,yy); 19 if(x!=xx){ 20 k=double(yy-y)/(double)(xx-x); 21 b=(double)y-k*(double)x; 22 } 23 else if(y>yy) swap(y,yy); 24 } 25 double f(double pos){return k*pos+b;} 26 27 }in[100010]; 28 int tree[160000],id[40000]; 29 void find(int l,int r,int pos){ 30 if(tree[pos]){ 31 if(in[tree[pos]].f(st)>mx){ 32 mx=in[tree[pos]].f(st); 33 ans=tree[pos]; 34 } 35 else if(in[tree[pos]].f(st)==mx){ 36 ans=min(ans,tree[pos]); 37 } 38 } 39 if(l==r){ 40 if(mx<hi[st]) ans=id[st]; 41 else if(mx==hi[st]) ans=min(ans,id[st]); 42 return; 43 } 44 int mid=(l+r)/2,lson=pos*2,rson=pos*2+1; 45 if(st<=mid) find(l,mid,lson); 46 else find(mid+1,r,rson); 47 return; 48 } 49 void insert(int l,int r,int pos){ 50 if(st<=l&&r<=ed){ 51 if(tree[pos]==0){ 52 tree[pos]=cnt; 53 return; 54 } 55 double l1=in[cnt].f(l),l2=in[tree[pos]].f(l),r1=in[cnt].f(r),r2=in[tree[pos]].f(r); 56 int mid=(l+r)/2,lson=pos*2,rson=pos*2+1; 57 if(l1>l2&&r1>r2){tree[pos]=cnt;return;} 58 if(l1<=l2&&r1<=r2) return; 59 insert(l,mid,lson); 60 insert(mid+1,r,rson); 61 } 62 int mid=(l+r)/2,lson=pos*2,rson=pos*2+1; 63 if(st<=mid) insert(l,mid,lson); 64 if(mid<ed) insert(mid+1,r,rson); 65 return; 66 } 67 int main() 68 { 69 int n,i,t; 70 scanf("%d",&n); 71 for(i=1;i<=n;i++){ 72 scanf("%d",&t); 73 if(t==0){ 74 scanf("%d",&st); 75 st=(st+ans-1)%imod+1; 76 mx=-1000.0,ans=0; 77 find(1,imod,1); 78 printf("%d\n",ans); 79 } 80 else{ 81 in[++cnt].read(); 82 st=in[cnt].x,ed=in[cnt].xx; 83 if(st==ed){ 84 if(hi[st]<in[cnt].yy){ 85 hi[st]=in[cnt].yy; 86 id[st]=cnt; 87 } 88 } 89 else insert(1,imod,1); 90 } 91 } 92 }