最近在补数学和几何,没啥好写的,因为已经决定每天至少写一篇了,今天随便拿个题水水。

题目大意:给你N个边平行于坐标轴的矩形,求它们并的周长。(N<=5000)

思路:这个数据范围瞎暴力就过了,但我们是有文化的人,下面讲讲利用扫描线和线段树的简单O(NlogN)做法。

先讲扫描线。我们先只考虑横着的边,竖着的等会儿一样做就是了。我们假设有一条横着的直线(这条就是扫描线啦)从所有矩形的上方扫到所有矩形的下方,我们时刻维护这条线上各个位置分别被几个矩形覆盖,一开始肯定都是0,如果碰到一个矩形上方的边,我们先查看这条边上哪些部分还未被其他矩形覆盖,计入答案,然后把扫描线上的这一整条边的被覆盖次数加一;如果遇到一个矩形下方的边,同理我们先把扫描线上这一部分的被覆盖次数减一,看看那些部分已经未被其他矩形覆盖了(即被当前边最后覆盖),再计入答案,扫一遍所有矩形,就算完了。实现上我们可以把所有横的边拿出来,记下纵坐标和左右端点,以及是矩形上方还是下方的边,然后按纵坐标排个序就可以处理了。

那么如何维护呢?我们只要支持区间加减以及查询区间内0的个数,看上去线段树就能做,区间加减都是小Case,问题是如何查区间内0的个数?在区间加减的同时似乎不是很好维护。其实很简单,我们只要维护区间最小值和最小值个数就可以了,由我们维护的信息的意义可知,这些信息的最小值不会小于0,如果有0,查询最小值及个数时一定能被我们找到,维护最小值区间加减也很容易。网络上看见有人O(n)暴力维护的,还有线段树维护很多信息来计算的,感觉都不是很好,更有甚者在线段树上每次O(n)暴力维护,看了令人汗颜……

#include<cstdio>
#include<algorithm>
using namespace std;
#define MN 10000
#define MX 20000
#define L (k<<1)
#define R ((k<<1)+1)
struct work{int x,l,r,p;}x[MN+5],y[MN+5];
bool cmp(work a,work b){return a.x==b.x?a.p>b.p:a.x<b.x;}
struct data{int x,s;};
data operator+(data a,data b)
{if(a.x==b.x)return(data){a.x,a.s+b.s};return a.x<b.x?a:b;
}
struct node{int l,r,mk;data x;}t[MX*4+5];
inline void up(int k){t[k].x=t[L].x+t[R].x;}
inline void add(int k,int x){t[k].x.x+=x;t[k].mk+=x;}
inline void down(int k){if(t[k].mk)add(L,t[k].mk),add(R,t[k].mk),t[k].mk=0;}
void build(int k,int l,int r)
{t[k].l=l;t[k].r=r;if(l==r){t[k].x.s=1;return;}int mid=l+r>>1;build(L,l,mid);build(R,mid+1,r);up(k);
}
void renew(int k,int l,int r,int x)
{if(t[k].l==l&&t[k].r==r){add(k,x);return;}down(k);int mid=t[k].l+t[k].r>>1;if(r<=mid)renew(L,l,r,x);else if(l>mid)renew(R,l,r,x);else renew(L,l,mid,x),renew(R,mid+1,r,x);up(k);
}
data query(int k,int l,int r)
{if(t[k].l==l&&t[k].r==r)return t[k].x;down(k);int mid=t[k].l+t[k].r>>1;if(r<=mid)return query(L,l,r);if(l>mid)return query(R,l,r);return query(L,l,mid)+query(R,mid+1,r);
}
int n,ans;
void solve(work*x)
{for(int i=0;i<n;++i){if(x[i].p<0)renew(1,x[i].l,x[i].r,-1);data d=query(1,x[i].l,x[i].r);if(x[i].p>0)renew(1,x[i].l,x[i].r,1);ans+=d.x?0:d.s;}
}
int main()
{int i,x0,y0,x1,y1;scanf("%d",&n);for(i=0;i<n;++i){scanf("%d%d%d%d",&x0,&y0,&x1,&y1);x0+=MN;y0+=MN;x1+=MN;y1+=MN;x[i]=(work){y0,x0,x1-1,1};x[i+n]=(work){y1,x0,x1-1,-1};y[i]=(work){x0,y0,y1-1,1};y[i+n]=(work){x1,y0,y1-1,-1};}n<<=1;sort(x,x+n,cmp);sort(y,y+n,cmp);build(1,0,MX);solve(x);solve(y);printf("%d",ans);
}

转载于:https://www.cnblogs.com/ditoly/p/Rectangle-Union.html

[矩形并-扫描线-线段树]Picture相关推荐

  1. 【HDU5091】Beam Cannon,扫描线+线段树

    传送门 思路: 扫描线的经典问题 然而并不是很会做-- 对x坐标差分一下(例如(x,y)类型为1,(x+w,y)的类型就是-1,以便于之后扫描可以去除该点),然后对y坐标转化为正数(便于操作为线段树上 ...

  2. 【BZOJ3958】[WF2011]Mummy Madness 二分+扫描线+线段树

    [BZOJ3958][WF2011]Mummy Madness Description 在2011年ACM-ICPC World Finals上的一次游览中,你碰到了一个埃及古墓. 不幸的是,你打开了 ...

  3. 扫描线+线段树简介 AcWing 248窗内的星星题解

    ----出自南昌理工学院ACM集训队 这周学习了线段树和扫描线的解题方法,下面由小菜鸡简介一下: 一般扫描线的题目最简单的便是扫描线裸模板(一般来说的话:数据范围小),其次的话便是进行拓展成线段树+扫 ...

  4. POJ 1177 Picture [离散化+扫描线+线段树]

    http://poj.org/problem?id=1177 给若干矩形,求被覆盖的区域的周长. 将 y 坐标离散化后,按 x 坐标进行扫描.用线段树维护两个东西,当前竖线的叠加长度 len 和 条数 ...

  5. HDU 1542:Atlantis(扫描线+线段树 矩形面积并)***

    题目链接 题意 给出n个矩形,求面积并. 思路 使用扫描线,我这里离散化y轴,按照x坐标从左往右扫过去.离散化后的y轴可以用线段树维护整个y上面的线段总长度,当碰到扫描线的时候,就可以统计面积.这里要 ...

  6. hdu 4419 Colourful Rectangle (离散化扫描线线段树)

    Problem - 4419 题意不难,红绿蓝三种颜色覆盖在平面上,不同颜色的区域相交会产生新的颜色,求每一种颜色的面积大小. 比较明显,这题要从矩形面积并的方向出发.如果做过矩形面积并的题,用线段树 ...

  7. 清明梦超能力者黄YY[树链剖分+扫描线,线段树合并]

    清明梦超能力者黄YY 题目连接 https://www.nowcoder.com/acm/contest/206/I 暂时有两种做法. 算法一 涉及:树链剖分,扫描线 在一个线段的情况下,我们可以把一 ...

  8. POJ 1151 扫描线 线段树

    题意:给定平面直角坐标系中的N个矩形,求它们的面积并. 题解:建立一个四元组(x,y1,y2,k).(假设y1<y2)用来储存每一条线,将每一条线按x坐标排序.记录所有的y坐标以后排序离散化.离 ...

  9. [BZOJ4422][Cerc2015]Cow Confinement(扫描线+线段树)

    === === 这里放传送门 === === 题解 记得这题很久以前学长出过胡策..然后当时没做出来..然后照着题解打了一发然后怎么调怎么WA然后就弃了..当时的题解好像是用差分什么的?基本思路是对每 ...

最新文章

  1. UI控件无法响应点击等事件的探索
  2. 编写线程安全的Java缓存读写机制 (原创)
  3. golang中并发sync和channel
  4. 运维常见统计表模板(word版)
  5. 常用模块-----configparser subprocess
  6. Struts2-Action的基本流程
  7. git push -u origin master 上传出错问题
  8. 使用WeUI+JS 的label包含input触发两次的问题
  9. 生成随机长度字符串,比如密码等
  10. 通过Etcd+Confd自动管理Haproxy(多站点)
  11. abaqus质量缩放系数取值_ABAQUS-延性损伤模型模拟金属材料断裂
  12. Linux内核源码阅读之打开文件篇
  13. 定时器 Cron表达式
  14. Oracle 11g Rac搭建
  15. Linux内核分析学习路线总结(内核人员必看)
  16. 免费域名注册 freenom
  17. 使用laser_filters屏蔽车架
  18. 抖音、美团等大厂千万级用户的Android客户端架构演进之路—
  19. Linux网络-UDP/TCP协议详解
  20. PIE-engine 教程 ——使用阈值法加载指定区域的大蒜种植区域并统计其面积

热门文章

  1. android cne服务,Android内存优化-了解内存篇
  2. matlab colorbar采用对数,matlab colorbar的使用 | 學步園
  3. Java技术:为什么不推荐使用BeanUtils属性转换工具
  4. 操作系统:分享6 个“吓人”的 Linux 命令
  5. 程序员的10大编程技巧
  6. 计算机有关的文献检索题目,文献检索第二次计算机检索实习题目(2016.4.10).doc
  7. python[进阶] 6.使用一等函数实现设计模式
  8. linux第一章简答
  9. yum安装Mariadb,二进制安装Mariadb
  10. SparkSQL 之 Shuffle Join 内核原理及应用深度剖析-Spark商业源码实战