zoukankan      html  css  js  c++  java
  • HDOJ 3265 Posters (线段树+扫描线求矩形面积并)

    题意:给n个矩形,每个矩形都有一个矩形的“洞”,矩形和洞的边都与坐标轴平行,求这些带“洞”的矩形覆盖的面积。

    数据范围:n<=50000, 0<=x,y<=50000

    分析:这题本质还是求矩形面积并,因为一个带“洞”的矩形可以看成是4个矩形。由于矩形数目n和坐标范围均比较大,所以离散化+暴力统计的方法肯定会超时。扫描线的方法我也是第一次学,我的理解是这样的,把所有矩形的2条竖直边(横边也一样)无限延伸就得到扫描线,这些线把所有矩形重新划分为许多不相交的矩形,所有矩形的面积并其实就是夹在这些线之间的矩形的面积之和,夹缝中的矩形的宽就是扫描线之间的距离,关键在于夹缝中矩形的高度是多少?这就要用到线段树了,由于坐标范围和矩形数目是一个数量级的,所以不离散化应该也没关系(我写了离散化)。线段树是根据y轴来建的,保存的关键信息就是当前夹缝中的矩形的高,其实就是区间的覆盖长度,另需保存区间被覆盖的次数以便更新。将从左到有扫描竖线,碰到矩形的左边竖线就覆盖到区间中,碰到右边竖线就将其从区间中删除,这样的话每次查询的区间被覆盖的长度就是夹缝中矩形的高。

    注意:

    1、建树之前要判断y方向上的坐标数目是否小于2,小于2时若建树会RE。其实小于2说明结果是0

    2、最大面积为500000*50000,超了int,可以用unsigned int

    View Code
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #define N 200010
    int n;
    struct scan
    {
        int x,yl,yu,flag;
    };
    scan scanline[2*N];
    int xcnt;
    int cnt[4*2*N],len[4*2*N];
    int y[2*N],ycnt;
    int cmp1(const void *a,const void *b)
    {
        return *(int*)a-*(int*)b;
    }
    int cmp2(const void *a,const void *b)
    {
        scan *c=(scan *)a;
        scan *d=(scan *)b;
        return (c->x)-(d->x);
    }
    void init()
    {
        xcnt=ycnt=0;
    }
    void add(int a,int b,int c,int d)
    {
        scanline[xcnt].x=a;
        scanline[xcnt].yl=b;
        scanline[xcnt].yu=d;
        scanline[xcnt++].flag=1;
    
        scanline[xcnt].x=c;
        scanline[xcnt].yl=b;
        scanline[xcnt].yu=d;
        scanline[xcnt++].flag=0;
    
        y[ycnt++]=b;    y[ycnt++]=d;
    }
    void read()
    {
        int i,j;
        int x[8];
        for(i=0;i<n;i++)
        {
            for(j=0;j<8;j++)    scanf("%d",&x[j]);
            if(x[0]<x[4] && x[1]<x[3])    add(x[0],x[1],x[4],x[3]);
            if(x[6]<x[2] && x[1]<x[3])    add(x[6],x[1],x[2],x[3]);
            if(x[4]<x[6] && x[7]<x[3])    add(x[4],x[7],x[6],x[3]);
            if(x[4]<x[6] && x[1]<x[5])    add(x[4],x[1],x[6],x[5]);
        }
    }
    int bs(int k)
    {
        int min=0,max=ycnt,mid;
        while(min+1!=max)
        {
            mid=min+max>>1;
            if(y[mid]>k)    max=mid;
            else    min=mid;
        }
        return min+1;
    }
    
    void update(int cur,int l,int r)
    {
        int ls=cur<<1,rs=cur<<1|1;
        if(cnt[cur]>0)  len[cur]=y[r-1]-y[l-1];
        else if(l+1==r) len[cur]=0;
        else    len[cur]=len[ls]+len[rs];
    }
    void build(int cur,int l,int r)
    {
        int mid=l+r>>1,ls=cur<<1,rs=cur<<1|1;
        cnt[cur]=0;
        len[cur]=0;
        if(l+1==r)  return;
        build(ls,l,mid);
        build(rs,mid,r);
    }
    void insert(int cur,int l,int r,int s,int t)
    {
        int mid=l+r>>1,ls=cur<<1,rs=cur<<1|1;
        if(l>=s && r<=t)
        {
            cnt[cur]++;
            update(cur,l,r);
            return;
        }
    
        if(mid>s)   insert(ls,l,mid,s,t);
        if(mid<t)   insert(rs,mid,r,s,t);
        update(cur,l,r);
    }
    void del(int cur,int l,int r,int s,int t)
    {
        int mid=l+r>>1,ls=cur<<1,rs=cur<<1|1;
        if(l>=s && r<=t)
        {
            cnt[cur]--;
            update(cur,l,r);
            return;
        }
    
        if(mid>s)   del(ls,l,mid,s,t);
        if(mid<t)   del(rs,mid,r,s,t);
        update(cur,l,r);
    }
    
    void solve()
    {
        qsort(y,ycnt,sizeof(y[0]),cmp1);
        qsort(scanline,xcnt,sizeof(scanline[0]),cmp2);
    
        int i,j,k;
        k=ycnt;
        ycnt=0;
        y[ycnt++]=y[0];
        for(i=1;i<k;i++)    if(y[ycnt-1]^y[i])  y[ycnt++]=y[i];
    
        if(ycnt<2)  {   puts("0");  return; }
    
        unsigned int ans=0;
        build(1,1,ycnt);
        for(k=0;k<xcnt-1;k++)
        {
            i=scanline[k].yl;   i=bs(i);
            j=scanline[k].yu;   j=bs(j);
            if(scanline[k].flag)    insert(1,1,ycnt,i,j);
            else    del(1,1,ycnt,i,j);
    
            i=scanline[k].x;
            j=scanline[k+1].x;
            ans+=len[1]*(j-i);
        }
        printf("%u\n",ans);
    }
    int main()
    {
        while(scanf("%d",&n),n)
        {
            init();
            read();
            solve();
        }
        return 0;
    }
  • 相关阅读:
    TCP/UDP 协议,和 HTTP、FTP、SMTP,区别及应用场景
    ZeroMQ使用汇总
    C/C++ 笔试、面试题目大汇总
    Caffe+Windows 环境搭建收集
    轻松看懂机器学习十大常用算法
    Caffe学习系列——工具篇:神经网络模型结构可视化
    深度神经网络可视化工具集锦
    MIT一牛人对数学在机器学习中的作用给的评述
    A Full Hardware Guide to Deep Learning
    Caffe上手教程
  • 原文地址:https://www.cnblogs.com/algorithms/p/2624147.html
Copyright © 2011-2022 走看看