题目链接:点击查看

题目大意:中文题面,简单明了,不多赘述

题目分析:这个题可以理解为Atlantis的升级版,其实完全可以对Atlantis这道题目的代码稍加修改就可以交上这个题,关键是如何修改?一开始我想用lazy标记将覆盖的次数下传,这样就能让每个区间都能正确判断了,可是出现了点小问题就是,如果lazy标记只是标记了,但是却没有及时下传,那么将会无法及时返回正确的覆盖长度,导致结果错误,那么我又想暴力一点,即每次更新区间的覆盖次数时,不使用lazy标记了,直接更新到叶子节点,完成更新后在上传更新,这样还真让我给过了,一会会放上代码,就是多了一个pushdown的过程。

但是这样并不完美,如果这个题想卡我时间,完全可以把我卡死在暴力的这条路上,所以我又去网上搜大牛的题解,发现了一种很巧妙的方法,代替了lazy标记但是却完成了lazy标记的任务,那就是在线段树中维护两个变量,一个是len,表示相应区间被覆盖大于等于1次的长度,还有一个变量lenlen,表示相应区间被覆盖大于等于2次的长度,这样一来,cover变量就会出现三种情况,分别是0,1,大于等于2,下面分情况讨论一下

  1. cover大于等于2的时候最简单,就是该区间已经被覆盖了两次及以上,这样lenlen的长度就便是区间的长度;
  2. 在分节点性质讨论,若当前节点为叶子节点,当cover为0或1时,因为叶子节点下面没有可以重叠的区间了,所以lenlen=0;
  3. 若当前节点不是叶子节点,当cover为1时,说明当前区间已经被覆盖过一次了,我们只需要查找子区间内被覆盖过1次的,取交集便是当前区间覆盖超过两次的长度了;
  4. 若当前节点不是叶子节点,当cover为0时,说明当前区间没有被覆盖过,所以我们只需要查找子区间内被覆盖超过2次的,取并集便是当前区间覆盖超过两次的长度了;

以上就是pushup函数的大体思路了,上代码对照着看吧:


暴力更新:

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<map>
#include<cmath>
#include<set>
#include<sstream>
using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=2100;struct Node
{int l,r;double ll,rr,len;int cover,lazy;
}tree[N<<2];vector<double>v;struct node
{double x,down,up;int into;node(){x=down=up=0;into=0;}bool operator<(node a)const{return x<a.x;}
}p[N];void build(int k,int l,int r)
{tree[k].l=l;tree[k].r=r;tree[k].ll=v[l-1];tree[k].rr=v[r-1];tree[k].len=0;tree[k].cover=0;tree[k].lazy=0;if(l+1==r)return;int mid=(l+r)>>1;build(k<<1,l,mid);build(k<<1|1,mid,r);
}void pushup(int k)
{if(tree[k].cover>1)tree[k].len=tree[k].rr-tree[k].ll;else if(tree[k].l+1==tree[k].r)tree[k].len=0;elsetree[k].len=tree[k<<1].len+tree[k<<1|1].len;
}void pushdown(int k,int val)//这里暴力更新到叶子节点
{if(tree[k].l+1==tree[k].r){tree[k].cover+=val;pushup(k);return;}pushdown(k<<1,val);pushdown(k<<1|1,val);pushup(k);
}void update(int k,int l,int r,int val)
{if(tree[k].l>r||tree[k].r<l)return;if(tree[k].l>=l&&tree[k].r<=r){pushdown(k,val);return;}update(k<<1,l,r,val);update(k<<1|1,l,r,val);pushup(k);
}int main()
{
//  freopen("input.txt","r",stdin)int w;cin>>w;int n;while(w--){scanf("%d",&n);v.clear();for(int i=1;i<=n;i++){double x1,x2,y1,y2;scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);p[i].x=x1;p[i+n].x=x2;p[i].up=p[i+n].up=y2;p[i].down=p[i+n].down=y1;p[i].into=1;p[i+n].into=-1;v.push_back(y1);v.push_back(y2);}sort(v.begin(),v.end());v.erase(unique(v.begin(),v.end()),v.end());int len=v.size();sort(p+1,p+2*n+1);build(1,1,len);double ans=0;for(int i=1;i<=2*n;i++){
//          cout<<tree[1].len*(p[i].x-p[i-1].x)<<endl;ans+=tree[1].len*(p[i].x-p[i-1].x);int l=lower_bound(v.begin(),v.end(),p[i].down)-v.begin()+1;int r=lower_bound(v.begin(),v.end(),p[i].up)-v.begin()+1;update(1,l,r,p[i].into);}printf("%.2f\n",ans);}return 0;
}

成段更新:

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<map>
#include<cmath>
#include<set>
#include<sstream>
using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=2100;struct Node
{int l,r;double ll,rr,len,lenlen;int cover;
}tree[N<<2];vector<double>v;struct node
{double x,down,up;int into;node(){x=down=up=0;into=0;}bool operator<(node a)const{return x<a.x;}
}p[N];void build(int k,int l,int r)
{tree[k].l=l;tree[k].r=r;tree[k].ll=v[l-1];tree[k].rr=v[r-1];tree[k].len=0;tree[k].cover=0;if(l+1==r)return;int mid=(l+r)>>1;build(k<<1,l,mid);build(k<<1|1,mid,r);
}void pushup(int k)
{if(tree[k].cover)//先处理被覆盖过的区间,只要被覆盖过了就肯定至少被覆盖过1次tree[k].len=tree[k].rr-tree[k].ll;else if(tree[k].l+1==tree[k].r)tree[k].len=0;elsetree[k].len=tree[k<<1].len+tree[k<<1|1].len;
/***********************************************************************/if(tree[k].cover>1)//再处理被覆盖过2次的区间,和上面同理tree[k].lenlen=tree[k].rr-tree[k].ll;else if(tree[k].l+1==tree[k].r)tree[k].lenlen=0;else if(tree[k].cover==1)tree[k].lenlen=tree[k<<1].len+tree[k<<1|1].len;elsetree[k].lenlen=tree[k<<1].lenlen+tree[k<<1|1].lenlen;
}void update(int k,int l,int r,int val)
{if(tree[k].l>r||tree[k].r<l)return;if(tree[k].l>=l&&tree[k].r<=r){tree[k].cover+=val;pushup(k);return;}update(k<<1,l,r,val);update(k<<1|1,l,r,val);pushup(k);
}int main()
{
//  freopen("input.txt","r",stdin)int n;int w;cin>>w;while(w--){scanf("%d",&n);v.clear();for(int i=1;i<=n;i++){double x1,x2,y1,y2;scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);p[i].x=x1;p[i+n].x=x2;p[i].up=p[i+n].up=y2;p[i].down=p[i+n].down=y1;p[i].into=1;p[i+n].into=-1;v.push_back(y1);v.push_back(y2);}sort(v.begin(),v.end());v.erase(unique(v.begin(),v.end()),v.end());int len=v.size();sort(p+1,p+2*n+1);build(1,1,len);double ans=0;for(int i=1;i<=2*n;i++){ans+=tree[1].lenlen*(p[i].x-p[i-1].x);int l=lower_bound(v.begin(),v.end(),p[i].down)-v.begin()+1;int r=lower_bound(v.begin(),v.end(),p[i].up)-v.begin()+1;update(1,l,r,p[i].into);}printf("%.2f\n",ans);}return 0;
}

HDU - 1255 覆盖的面积(线段树+扫描线)相关推荐

  1. HDU1255 覆盖的面积 (线段树 + 扫描线)

    题目链接:覆盖的面积 大致题意 现在有平面直角坐标系xoy, 有n个平行于x轴y轴的矩形, 给出这些矩形的左上角和右下角的坐标, 让你求出这些矩形组成的图形中被至少两个矩形覆盖的部分的总面积. 解题思 ...

  2. HDU - 1255 覆盖的面积(线段树求矩形面积交 扫描线+离散化)

    链接:线段树求矩形面积并 扫描线+离散化 1.给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. 2.看完线段树求矩形面积并 的方法后,再看这题,求的是矩形面积交,类同. 求面积时,用被覆 ...

  3. HDU 1264 Counting Squares (线段树-扫描线-矩形面积并)

    版权声明:欢迎关注我的博客.本文为博主[炒饭君]原创文章,未经博主同意不得转载 https://blog.csdn.net/a1061747415/article/details/25471349 P ...

  4. HDU 1255 覆盖的面积(线段树+扫描线)

    题目地址:HDU 1255 这题跟面积并的方法非常像,仅仅只是须要再加一个变量. 刚開始我以为直接用那个变量即可,仅仅只是推断是否大于0改成推断是否大于1.可是后来发现了个问题,由于这个没有下放,没延 ...

  5. hdu 1255 覆盖的面积 (扫描线求矩形交)

    覆盖的面积 Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Sub ...

  6. hdu 1255 覆盖的面积

    覆盖的面积 Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Sub ...

  7. hdu 1255 覆盖的面积 (Bruceforce)

    Problem - 1255 暴力统计覆盖超过一次的区域.1y. 代码如下: 1 #include <cstdio> 2 #include <cstring> 3 #inclu ...

  8. hdu 1542 Atlantis (线段树+扫描线)

    http://acm.hdu.edu.cn/showproblem.php?pid=1542 单纯的线段树+扫描线求面积并,需要离散化. code: #include <cstdlib> ...

  9. hdu1542 线段树扫描线求矩形面积的并

    题意:       给你n个正方形,求出他们的所占面积有多大,重叠的部分只能算一次. 思路:       自己的第一道线段树扫描线题目,至于扫描线,最近会写一个总结,现在就不直接在这里写了,说下我的方 ...

最新文章

  1. 开源 java CMS - FreeCMS2.6 静态化管理
  2. HDU 3632 A Captivating Match
  3. JavaScript 基础,登录前端验证
  4. 如何用ARKit将太阳系装进iPhone(二)
  5. Java高并发编程详解系列-Java线程入门
  6. 理论篇-数理统计填坑篇
  7. SpringMVC框架、Spring boot框架、SSM區別
  8. GitHub 下架 Youtube-dl 遭粉丝疯狂上传源码报复,开源者的权益谁来维护?
  9. python统计文本单词总数_python统计文本文件内单词数量的方法
  10. 3、贝叶斯优化相关理论知识
  11. 层次分析法(AHP)原理_例题应用及代码
  12. html鼠标点击后变换样式,css鼠标样式(css鼠标点击切换样式)
  13. 教你解决微信跳转appstore的困扰
  14. 下一代 Web 应用模型 — Progressive Web App
  15. js的lambda表达式
  16. 戴姆勒与Infosys结成战略合作伙伴关系,推动创新及IT基础设施转型
  17. 在计算机中文字的表示
  18. 浏览器中的data类型的Url格式,data:image/png,data:image/jpeg!
  19. 程序员之间的战争,某宁测试和开发干架,鼠标线勒脖子都来了!
  20. 统计制表符、空格和换行符的个数

热门文章

  1. MySQL模糊查询—between and关键字
  2. MyBatis 源码解读-settingsAsProperties()
  3. IDEA 集成Lombok 插件-使用插件
  4. RequestToViewNameTranslator
  5. Spring5各模块之间的依赖关系
  6. Redis中的淘汰策略
  7. MyBatis开发步骤
  8. (常用API)正则表达式练习和相关的String类方法
  9. Redis实现分布式锁释放锁
  10. php 验证 e mail,PHP 表单验证 - 验证 E-mail 和 URL