线段树+扫描线

经典的扫描线问题

首先将一个矩形看作由竖着的两条边和横着的两条边构成

那分成两次考虑,一次考虑竖边,一次考虑横边

首先考虑横边

如图两个矩形,现将横边擦去,留下竖边,将平面划分成3个区域

在代码实现时,可以从左到右记录端点

那么现在想象一条平行于横边的扫描线不断从下往上扫

当扫到一个矩形的下边,将这条矩形的下边包含的区间覆盖

当扫到一个矩形的上边,将这条矩形的上边包含的区间去除覆盖

那么对于这些被竖线划分的区域,建立一棵线段树维护这些区间是否被覆盖

如最底下的矩形下边,覆盖区间2,3

那么如何统计答案

答案就是上一次线段树维护的总区间被覆盖的长度-当前线段树维护的总区间覆盖的长度的绝对值

如上图,扫描到第2边,上一次覆盖2,3,那此处增加为1区间

那么线段树中维护这个区间被完全覆盖的次数和被覆盖的长度即可

#include <iostream>
#include <algorithm>
#include <map>
#include <cstdio>
#define inf (int)1e9
using namespace std;
int n,w,last,ans;
struct node
{
int a,b,c,d;
}p[5100];
struct tree
{
int l,r,sum;
int len;
}sh[100000];
struct edge
{
int l,r,num,kind;
}a[11000];
bool cmp(edge a,edge b)
{
return (a.num<b.num || (a.num==b.num && a.kind>b.kind));//注意如果同一高度的话,先处理下边的
}
void pushup(int x)
{
if (sh[x].sum>0)//如果当前被完全覆盖,那么当前区间被覆盖的长度为r-l+1
sh[x].len=sh[x].r-sh[x].l+1;
else
if (sh[x].l==sh[x].r)//叶子结点
sh[x].len=0;
else
sh[x].len=sh[x+x].len+sh[x+x+1].len;//一般情况
}
void build(int x,int ll,int rr)
{
sh[x].l=ll;
sh[x].r=rr;
sh[x].sum=sh[x].len=0;
if (ll==rr)
return;
int mid;
mid=(ll+rr)>>1;
build(x+x,ll,mid);
build(x+x+1,mid+1,rr);
}
void change(int x,int ll,int rr,int v)
{
if (sh[x].l>=ll && sh[x].r<=rr)
{
sh[x].sum+=v;
pushup(x);
return;
}
int mid;
mid=(sh[x].l+sh[x].r)>>1;
if (ll<=mid)
change(x+x,ll,rr,v);
if (rr>mid)
change(x+x+1,ll,rr,v);
pushup(x);
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d%d%d%d",&p[i].a,&p[i].b,&p[i].c,&p[i].d);
for (int i=1;i<=n;i++)//记录前扫描线要扫到的边
{
w++;
a[w].l=p[i].a;a[w].r=p[i].c;
a[w].kind=1;a[w].num=p[i].b;//下边
w++;
a[w].l=p[i].a;a[w].r=p[i].c;
a[w].kind=-1;a[w].num=p[i].d;//上边
}
build(1,-10000,10000);
sort(a+1,a+1+w,cmp);
last=0;//上一次答案
for (int i=1;i<=w;i++)
{
change(1,a[i].l,a[i].r-1,a[i].kind);
ans+=abs(last-sh[1].len);
last=sh[1].len;
}
w=0;//处理竖边
for (int i=1;i<=n;i++)
{
w++;
a[w].l=p[i].b;a[w].r=p[i].d;
a[w].kind=1;a[w].num=p[i].a;
w++;
a[w].l=p[i].b;a[w].r=p[i].d;
a[w].kind=-1;a[w].num=p[i].c;
}
build(1,-10000,10000);
sort(a+1,a+1+w,cmp);
last=0;
for (int i=1;i<=w;i++)
{
change(1,a[i].l,a[i].r-1,a[i].kind);
ans+=abs(last-sh[1].len);
last=sh[1].len;
}
printf("%d\n",ans);
}

最新文章

  1. CSS清除浮动
  2. Activity生命周期(深入理解)
  3. 根据value选择select
  4. Android中的Shape使用总结
  5. Web技术导论复习大纲
  6. 启用PowerShell Web Access
  7. 我是如何学习NodeJs
  8. Azure 网站和通配符域
  9. poj 2182 Lost Cows(段树精英赛的冠军)
  10. java开发地三天——数据库介绍
  11. 异常详细信息: Abp.AbpException: No language defined!
  12. pytorch中文文档-torch.nn常用函数-待添加-明天继续
  13. 图文详解之ZSH美化你的终端CLI
  14. Python threading(多线程)
  15. utf-8 编码问题
  16. JS操作DOM节点大全
  17. 两个非常好的bootstrap模板,外送大话设计模式!
  18. 【.NetCore学习】ubuntu16.04 搭建.net core mvc api 运行环境
  19. [daily][archlinux][game] 几个linux下还不错的游戏
  20. git设置ss代理

热门文章

  1. Linux系统编程—信号集操作函数
  2. 【题解】NOIP2018 旅行
  3. java安全编码指南之:输入注入injection
  4. redis 开启AOF
  5. 要是想让程序跳转到绝对地址是0x100000去执行
  6. 华为方舟编译器正式支持C语言:完全开源
  7. 发布MeteoInfo Java 1.2.1
  8. day52 Pyhton 前端03
  9. 界面酷炫,功能强大!这款 Linux 性能实时监控工具超好用!
  10. Linux下快速搭建测试网站DVWA