• 暑假集训Day3 G(树状数组扫描线)


    题目链接在本地,题目大意就是给了n个矩形,问是否存在两个矩形,它们的边有相交(注:回字形嵌套的边没有相交)

    依旧是非常经典的扫描线问题,不过传统的扫描线是用来求矩形面积之和的,但是对于这道题,我们需要判断给定一个区间,其上是否存在线段,存在几个线段,因此不能用传统的方法去想。猫猫想了一个很有趣的方法,类似于差分约束,但又完全不同,即如果插入一条线段,则在线段的左端点加一,右端点也加一,判断一个区间上是否完整有一条线段的方法就是用树状数组查询两个端点,然后求差,如果差为0则没有完全包含一条线段。这个思想非常值得学习,判断一个区间内是否有线段。

    另一个需要学习的就是离散化和stl二分的方法,在扫描线的问题中极其常见。

     1 #include "bits/stdc++.h"
     2 using namespace std;
     3 const int MAX=2e5+5;
     4 int n,c[MAX<<1],bas[MAX<<1],cnt,m;
     5 bool flag;
     6 struct Edge{
     7     int x,y,h,tg;
     8     bool operator < (const Edge &tt) const {
     9         return h<tt.h;
    10     }
    11 }edge[MAX];
    12 void update(int x,int y){ for (;x<=m;x+=(x&-x)) c[x]+=y; }
    13 int search(int x){int an=0;for (;x>0;x-=(x&-x)) an+=c[x]; return an;}
    14 int main(){
    15 //    freopen ("g.in","r",stdin);
    16 //    freopen ("g.out","w",stdout);
    17     int i,j,x1,y1,x22,y2,ll,rr;
    18     scanf("%d",&n);
    19     cnt=m=0; flag=true;
    20     for (i=1;i<=n;i++){
    21         scanf("%d%d%d%d",&x1,&y1,&x22,&y2);
    22         cnt++;
    23         edge[cnt].x=x1,edge[cnt].y=x22,edge[cnt].h=y1,edge[cnt].tg=1;
    24         cnt++;
    25         edge[cnt].x=x1,edge[cnt].y=x22,edge[cnt].h=y2,edge[cnt].tg=-1;
    26         bas[++m]=x1,bas[++m]=x22,bas[++m]=y1,bas[++m]=y2;
    27     }
    28     sort(edge+1,edge+cnt+1);
    29     sort(bas+1,bas+m+1);
    30     m=unique(bas+1,bas+m+1)-(bas+1);
    31     memset(c,0,sizeof(c));
    32     for (i=1;i<=cnt;i++){
    33         ll=lower_bound(bas+1,bas+m+1,edge[i].x)-bas;
    34         rr=lower_bound(bas+1,bas+m+1,edge[i].y)-bas;
    35         if (edge[i].tg==1){
    36             if (search(ll)!=search(rr)){
    37                 flag=false;
    38                 break;
    39             }
    40             update(ll,edge[i].tg);
    41             update(rr,edge[i].tg);
    42         }
    43         else{
    44             update(ll,edge[i].tg);
    45             update(rr,edge[i].tg);
    46             if (search(ll)!=search(rr)){
    47                 flag=false;
    48                 break;
    49             }
    50         }
    51     }
    52     if (flag) printf("0");
    53     else printf("1");
    54     return 0;
    55 }
  • 相关阅读:
    三列自适应等高且中列宽度自适
    两列高度自适应(转)
    Transform 1
    跟我一起透彻理解template模板模式
    走进C++程序世界-----operator new delete 重载
    linux下maven的安装
    JavaScript权威指南第01章 JavaScript 概述
    切勿辜负青春一场
    C++ 模板应用 实现一个Queue 队列
    从头认识java-14.4 Java提供的数组的有用功能(2)
  • 原文地址:https://www.cnblogs.com/keximeiruguo/p/16456090.html
Copyright © 2020-2023  润新知