• 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
    ",ans);
    104             else puts("Human intelligence is really terrible");
    105     return 0;
    106 }
    View Code
  • 相关阅读:
    实验6 继承
    实验5 运算符重载
    实验4 类初步
    实验3 文件操作
    实验2 C++数组与指针
    实验1 C++函数
    C++程序设计实验安排
    计算机图形学课件pdf版
    《三维建模简介》课件
    《3D建模初步》参考资料
  • 原文地址:https://www.cnblogs.com/zhuchenrui/p/7654365.html
Copyright © 2020-2023  润新知