YYHS-Super Big Stupid Cross(二分+掃描線+平衡樹)
阿新 • • 發佈:2017-10-12
[] div cst ans c++ name real style 附加
第一行,一個正整數 N,代表線段的數目。
以下 N 行,每行四個整數 x1,y1,x2,y2(x1=x2 或 y1=y2) ,描述了一條線段。
3
-1 0 5 0
0 -1 0 1
2 -2 2 2
【樣例輸出 2】
2
【樣例輸入輸出 3】
見附加文件 cross.in/ans。
【數據規模與約定】
對於 50%的數據:N≤1000。
對於 100%的數據:1≤N≤100000,所有坐標的範圍在-10^9~10^9 中。
後 50%內,所有數據均為隨機生成。
題目描述
“我是超級大沙茶”——Mato_No1 為了證明自己是一個超級大沙茶,Mato 神犇決定展示自己對叉(十字型)有多麽的了 解。 Mato 神犇有一個平面直角坐標系,上面有一些線段,保證這些線段至少與一條坐標軸 平行。Mato 神犇需要指出,這些線段構成的最大的十字型有多大。 稱一個圖形為大小為 R(R 為正整數)的十字型,當且僅當,這個圖形具有一個中心點, 它存在於某一條線段上,並且由該點向上下左右延伸出的長度為 R 的線段都被已有的線段 覆蓋。 你可以假定:沒有兩條共線的線段具有公共點,沒有重合的線段。
輸入
輸出
當不存在十字型時:輸出一行“Human intelligence is really terrible” (不包括引號) 。 否則:輸出一行,一個整數,為最大的 R。
樣例輸入
1 0 0 0 1樣例輸出
Human intelligence is really terrible提示
【樣例輸入 2】
3
-1 0 5 0
0 -1 0 1
【樣例輸出 2】
2
【樣例輸入輸出 3】
見附加文件 cross.in/ans。
【數據規模與約定】
對於 50%的數據:N≤1000。
對於 100%的數據:1≤N≤100000,所有坐標的範圍在-10^9~10^9 中。
後 50%內,所有數據均為隨機生成。
題解
這道題可以暴力水過,正解是二分+掃描線+平衡樹
網上看到的題解都是暴力的,這裏寫一下正解的算法
讀入的時候我們先把橫的和豎的線都找出來,並且存一下每條線的len和兩端的位置(如果是橫的就記錄x1,x2,豎的就記錄y1,y2)
然後我們二分答案,每次check的時候,把所有線段都減去2*二分的長度(因為兩邊都要減)並加到新數組裏(橫的歸橫的,豎的歸豎的),這裏我們還要多加一個id值,在之後能用到,如果某條線段的長度不夠了,就不用把這條線加到數組裏面了
這裏我用th[]記錄橫的線,ts[]記錄豎的線
加到數組中後,我們就開始掃描,掃描到橫的線的左端就把這條線的y坐標加入到平衡樹上(可以用c++的set),掃描到豎的線就查找lower_bound(這條線的下端點),判斷一下找到的值是否<=這條線的上端點,如果掃到橫的線的右端就把這條線的y坐標從平衡樹上刪去
因為坐標的範圍很大,我們不能直接枚舉坐標,所以我們可以按橫的線的左端和右端分別排個序,用L[]和R[]存一下,每次用指針往後找就可以了,至於多加的id值,因為排過序,橫的線的次序就打亂了,所以我們在加入到數組後直接用另一個數組把th[]存下來,這樣每次查詢id的時候就可以找到原來的th[].id了
說了那麽多,來看看代碼吧(可能會好懂一些)
1 #include<algorithm> 2 #include<cstdio> 3 #include<cstring> 4 #include<set> 5 #define N 100005 6 using namespace std; 7 int n,x1,x2,y1,y2,cnt1,cnt2,l,r,ans,nums,numh; 8 multiset<int> q; 9 typedef set<int>::iterator It; 10 struct node{ 11 int x,l,r,len; 12 }s[N],ts[N]; 13 struct Node{ 14 int y,l,r,len,id; 15 }h[N],th[N],Th[N]; 16 struct NODE{ 17 int p,id; 18 }L[N],R[N]; 19 bool cmp(node x,node y){ return x.x<y.x; } 20 bool cmp1(Node x,Node y){ 21 if (x.l!=y.l) return x.l<y.l; 22 else return x.r<y.r; 23 } 24 bool cmp2(Node x,Node y){ 25 if (x.r!=y.r) return x.r<y.r; 26 else return x.l<y.l; 27 } 28 void pre(int len){ 29 nums=numh=0; 30 for (int i=1;i<=cnt1;i++) 31 if (s[i].len>=2*len){ 32 ts[++nums].x=s[i].x; 33 ts[nums].len=s[i].len-2*len; 34 ts[nums].l=s[i].l+len; ts[nums].r=s[i].r-len; 35 } 36 for (int i=1;i<=cnt2;i++) 37 if (h[i].len>=2*len){ 38 th[++numh].y=h[i].y; 39 th[numh].len=h[i].len-2*len; 40 th[numh].l=h[i].l+len; th[numh].r=h[i].r-len; 41 th[numh].id=numh;//加入的id值 42 } 43 memcpy(Th,th,sizeof(th));//用臨時數組把th存下來,因為之後th數組會被排序 44 } 45 bool check(int len){ 46 q.clear(); 47 q.insert(1e9);//防止lower_bound找到0 48 pre(len); 49 sort(ts+1,ts+1+nums,cmp); 50 sort(th+1,th+1+numh,cmp1); 51 for (int i=1;i<=numh;i++) 52 L[i].p=th[i].l,L[i].id=th[i].id;//按左端點排序 53 sort(th+1,th+1+numh,cmp2); 54 for (int i=1;i<=numh;i++) 55 R[i].p=th[i].r,R[i].id=th[i].id;//按右端點排序 56 L[numh+1].p=R[numh+1].p=ts[nums+1].x=1e9;//防止越界 57 int x=1,y=1,z=1; 58 while (x<=numh||y<=numh||z<=nums){ 59 int a=0,b=0,c=0; 60 if (L[x+a].p<=R[y].p&&L[x+a].p<=ts[z].x){ 61 q.insert(Th[L[x].id].y); 62 a++; 63 while (L[x+a-1].p==L[x+a].p) q.insert(Th[L[x+a].id].y),a++;//把相同左端點的都加到set中 64 } 65 if (ts[z+c].x<=L[x].p&&ts[z+c].x<=R[y].p){ 66 It s=q.lower_bound(ts[z].l); 67 if (*s<=ts[z].r) return true; 68 c++; 69 while (ts[z+c-1].x==ts[z+c].x){//查詢,意義同上面 70 It s=q.lower_bound(ts[z+c].l); 71 if (*s<=ts[z+c].r) return true; 72 c++; 73 } 74 } 75 if (R[y].p<=L[x].p&&R[y].p<=ts[z].x){ 76 q.erase(Th[R[y].id].y); 77 b++; 78 while (R[y+b-1].p==R[y+b].p) q.erase(Th[R[y+b].id].y),b++;//刪除,意義同上 79 } 80 x+=a; y+=b; z+=c;//不能直接把指針向後移 81 } 82 return false; 83 } 84 int main(){ 85 scanf("%d",&n); 86 for (int i=1;i<=n;i++){ 87 scanf("%d%d%d%d",&x1,&y1,&x2,&y2); 88 if (x1>x2) swap(x1,x2); 89 if (y1>y2) swap(y1,y2); 90 if (x1==x2){ 91 s[++cnt1].x=x1; s[cnt1].l=y1; s[cnt1].r=y2; s[cnt1].len=y2-y1; 92 } else{ 93 h[++cnt2].y=y1; h[cnt2].l=x1; h[cnt2].r=x2; h[cnt2].len=x2-x1; 94 } 95 } 96 l=1; r=1e9; ans=1e9; 97 while (l<=r){ 98 int mid=(l+r)>>1; 99 if (check(mid)){ 100 ans=mid; l=mid+1; 101 } else r=mid-1; 102 } 103 if (ans!=1e9) printf("%d\n",ans); 104 else puts("Human intelligence is really terrible"); 105 return 0; 106 }View Code
YYHS-Super Big Stupid Cross(二分+掃描線+平衡樹)