YYHS-Super Big Stupid Cross(二分+扫描线+平衡树)

题目描述

“我是超级大沙茶”——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

 

posted @ 2017-10-12 07:12  I__am  阅读(570)  评论(0编辑  收藏  举报