1. 程式人生 > >YYHS-Super Big Stupid Cross(二分+掃描線+平衡樹)

YYHS-Super Big Stupid Cross(二分+掃描線+平衡樹)

[] div cst ans c++ name real style 附加

題目描述

“我是超級大沙茶”——Mato_No1 為了證明自己是一個超級大沙茶,Mato 神犇決定展示自己對叉(十字型)有多麽的了 解。 Mato 神犇有一個平面直角坐標系,上面有一些線段,保證這些線段至少與一條坐標軸 平行。Mato 神犇需要指出,這些線段構成的最大的十字型有多大。 稱一個圖形為大小為 R(R 為正整數)的十字型,當且僅當,這個圖形具有一個中心點, 它存在於某一條線段上,並且由該點向上下左右延伸出的長度為 R 的線段都被已有的線段 覆蓋。 你可以假定:沒有兩條共線的線段具有公共點,沒有重合的線段。

輸入

第一行,一個正整數 N,代表線段的數目。 以下 N 行,每行四個整數 x1,y1,x2,y2(x1=x2 或 y1=y2) ,描述了一條線段。

輸出

當不存在十字型時:輸出一行“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 2 2
【樣例輸出 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(二分+掃描線+平衡樹)