Bzoj 3165: [Heoi2013]Segment
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 }
Bzoj 3165: [Heoi2013]Segment