【IOI2014】Rail
阿新 • • 發佈:2021-11-03
分析
首先會想到,詢問一下0到其他車站的距離。容易發現距離最近的一定是0右邊的第一個 \(D\) 類車站,設為 \(p\)。
看看我們此時得到了什麼?在0到 \(p\) 車站之間的車站一定是 \(C\) 類車站(\(p\) 是0右邊的第一個 \(D\) 類)。還有其他的嗎?好像沒有了。
所以我們試圖問一下 \(p\) 到其他車站的距離以增加條件。
若 \(c\) 車站為 \(p\) 左邊的C類(無論是否在0左邊),有:\(dis_{0,c}=dis_{p,c}+dis_{0,p}\) 。如圖:
若c為D類,顯然有 \(dis_{0,c} \ge dis_{p,c}+dis_{0,p}\) 。於是可以確定一個車站是否在 \(p\)
現在的問題就只有如何確定每個車站是C還是D了(確定方向可用任意一個dis算真正位置)。
那我們假設 \(p\) 右邊的全是D類,把 \(p\) 右邊的按到 \(p\) 的距離排序後從左往右掃。設上一次確定的一個 \(D\) 類車站為 \(a\) ,從0到 \(a\) 之間的車站已確定,現在想求 \(x\) 車站的答案,有兩種情況 :
若x為D類,若詢問一下 \(a\) 到 \(x\) 的距離,那肯定是 \(a\) 到 \(mid\) ,再從 \(mid\) 到 \(x\) 。
若x為C類:
則 \(x\) 到 \(a\) 就是直接走的距離,但此時 \(mid\) 必須為D類,否則 \(dis_{0,x}\)
容易發現這兩種情況的 \(x\) 是關於 \(mid\) 對稱的,而一個點只有一個車站。又因為已知 \(dis_{0,x}\) 和 \(dis_{p,x}\) 用一些幾何方法求出 \(mid\) 的位置,再判斷型別即可。
時間複雜度:\(O(nlogn)\)。
code
#include<bits/stdc++.h> #include"rail.h" using namespace std; const int N=5000,INF=(1<<30),M=1e6; int dis0[N+5],disp[N+5],pos; int que[N+5],t,tag[M+5],t1,t2; //當處理右邊時,q用於存上一次確定的D類 struct node { int dis,id; bool operator < (const node &it) const { return dis<it.dis; } } l[N+5],r[N+5]; void add(int p) {tag[p]=1;} int find(int p) {return tag[p]!=-1;} void findLocation(int n, int first, int location[], int stype[]) { memset(tag,-1,sizeof tag); location[0]=first;stype[0]=1; if(n==1) return;dis0[0]=INF; for(int i=1; i<n; i++) { dis0[i]=getDistance(0,i); if(dis0[i]<dis0[pos]) pos=i; } for(int i=1; i<n; i++) if(i!=pos) disp[i]=getDistance(pos,i); location[pos]=first+dis0[pos];stype[pos]=2; for(int i=0; i<n; i++) { if(i==0||i==pos) continue; if(dis0[pos]+disp[i]==dis0[i]&&disp[i]<dis0[pos]) location[i]=location[pos]-disp[i],stype[i]=1; //[0,p]中間的C類可以直接確定 if(dis0[pos]+disp[i]==dis0[i]&&disp[i]>dis0[pos]) l[++t1]=node{disp[i],i}; //此時一定在0左邊。 if(dis0[pos]+disp[i]!=dis0[i]) r[++t2]=node{dis0[i],i}; //在p右邊 } sort(l+1,l+1+t1);sort(r+1,r+1+t2); if(t2) { location[que[t=1]=r[1].id]=first+r[1].dis;stype[r[1].id]=2; tag[location[r[1].id]]=1; for(int i=2; i<=t2; i++) { int tmp=getDistance(r[i].id,que[t]); int d=(dis0[que[t]]+tmp-dis0[r[i].id])/2; //求對稱點相對q[t]的位置 if(location[que[t]]-d>location[pos]&&tag[location[que[t]]-d]!=-1) //對稱點為D,則這個站為C location[r[i].id]=location[que[t]]-tmp,stype[r[i].id]=1; else location[r[i].id]=first+r[i].dis,stype[r[i].id]=2,tag[location[r[i].id]]=1,que[++t]=r[i].id; } } //處理右邊 if(t1) { location[que[t=1]=l[1].id]=location[pos]-l[1].dis;stype[l[1].id]=1; tag[location[l[1].id]]=1; for(int i=2; i<=t1; i++) { int tmp=getDistance(l[i].id,que[t]); int d=(disp[que[t]]+tmp-disp[l[i].id])/2; if(location[que[t]]+d<first&&tag[location[que[t]]+d]!=-1) location[l[i].id]=location[que[t]]+tmp,stype[l[i].id]=2; else location[l[i].id]=location[pos]-l[i].dis,stype[l[i].id]=1,tag[location[l[i].id]]=1,que[++t]=l[i].id; } } //基本同上 }