USACO Overplanting ( 线段树扫描线 )
题意 : 在二维平面上给出 N 个矩形,问你所有矩形构成的图案的面积是多少(相互覆盖的地方只计算一次)
分析 :
求矩形面积并可以模拟来做,不过使用线段树来辅助做扫描线可以更高效地求解
扫描线顾名思义就是类似有一条线在二维平面上扫过去,将矩形面积并给扫出来
实现是使用线段树来模拟这个扫描的过程
第一步就是确定扫描的方向,是从左到右扫还是从上到下扫,这里以从上到下为例
第二步就是确定题目的坐标是否可能很大,如果很大意味着线段树开不了,则要进行离散化操作
由于是从上到下,我们记录每个矩形的上下两条边的一些信息
此后将不再考虑矩形,而是从上到下考虑这些横线
此图引用了 ==>http://blog.csdn.net/u013480600/article/details/22548393
信息包括有矩形上下两条边的左右端点的横坐标值,以及两条线的纵坐标的值即高度
然后我们给两条边的上边和下边分别做个标记,标记的作用就是判断当前矩形是要计入还是删除
在扫到当前的边为上边的时候意味着要在线段树内进行区间加法,将这条线段的值累计到线段树中
在扫到当前的边为下边的时候意味着要在线段树内进行区间减肥,将这条线段的值从线段树中删去
此时线段树在从上到下扫的过程中就一直记录着有效的横坐标值,记得刚刚我们存储的横线的高度么?
只要将有效的横坐标值(线段之长)乘以上下两条边的高度之差便得到了当前两条线段之间的面积
#include<bits/stdc++.h> #define LL long long #define lson l, m, rt<<1 #define rson m+1,r,rt<<1|1 using namespace std; ; const int Base = 1e8; int add[maxn]; ]; ]; struct Node{ int flag; int l, r, h; Node(){}; Node(int L, int R, int H, int F):l(L),r(R),h(H),flag(F){}; bool operator < (const Node & rhs) const{ return this->h < rhs.h; }; }s[maxn]; inline void pushup(int rt, int l, int r) { ] - x[l];/// 这里每一个 l 和 r 是离散化后的值 /// 所以应当代入 x 数组来获取真实值 ; ] + sum[rt<<|]; } inline void update(int L, int R, int c, int l, int r, int rt) { int m; if(L <= l && r <= R){ add[rt] += c; pushup(rt, l, r); return ; } m = (l+r)>>; if(L <= m) update(L, R, c, lson); if(R > m) update(L, R, c, rson); pushup(rt, l, r); } int main(void) { int n; scanf("%d", &n); int x1, x2, y1, y2; ; ; i<n; i++){ scanf("%d %d %d %d", &x1, &y1, &x2, &y2); x1 += Base, x2 += Base, y1 += Base, y2 += Base;/// 因为有负数坐标的存在,所以需要加上一个基数 x[num] = x1;/// 记录所有出现的横坐标的值,方便离散化 s[num++] = Node(x1, x2, y1, ); /// 将所有的横边(与x轴平行)以及其高度存储起来 x[num] = x2; s[num++] = Node(x1, x2, y2, -);/// 顶边 flag == 1 而底边 flag == -1 是为了方便 /// 从上到下扫描的时候做到,计入及删除这个矩形操作 } sort(x, x+num); sort(s, s+num); int idx = std::unique(x, x+num) - x;/// 离散化横坐标 int L, R; ;/// Attention !!! ; i<num-; i++){ L = lower_bound(x, x+idx, s[i].l) - x;/// 找出线段树应当更新的左右界,注意是使用离散化后的值 R = lower_bound(x, x+idx, s[i].r) - x - ; update(L,R,s[i].flag,,idx-,);/// 根据 flag 来确定是要删除还是添加操作 ans+=(sum[]*(1LL*s[i+].h-1LL*s[i].h));/// 最后用当前存在的横坐标的总和去乘高度就是面积了,累加起来 } printf("%lld\n", ans); ; }
类似题目 : HDU 1542 Atlantis
#include<bits/stdc++.h> #define LL long long #define lson l, m, rt<<1 #define rson m+1,r,rt<<1|1 using namespace std; ; int add[maxn]; ], sum[maxn<<]; struct Node{ int flag; double l, r, h; Node(){}; Node(double L, double R, double H, int F):l(L),r(R),h(H),flag(F){}; bool operator < (const Node & rhs) const{ return this->h < rhs.h; }; }s[maxn]; inline void pushup(int rt, int l, int r) { ] - x[l]; ; ] + sum[rt<<|]; } inline void update(int L, int R, int c, int l, int r, int rt) { int m; if(L <= l && r <= R){ add[rt] += c; pushup(rt, l, r); return ; } m = (l+r)>>; if(L <= m) update(L, R, c, lson); if(R > m) update(L, R, c, rson); pushup(rt, l, r); } int main(void) { , n; while(~scanf("%d", &n) && n){ double x1, x2, y1, y2; ; ; i<n; i++){ scanf("%lf %lf %lf %lf", &x1, &y1, &x2, &y2); x[num] = x1; s[num++] = Node(x1, x2, y1, ); x[num] = x2; s[num++] = Node(x1, x2, y2, -); } sort(x, x+num); sort(s, s+num); int idx = std::unique(x, x+num) - x; memset(add, , sizeof(add)); memset(sum, , sizeof(sum)); int L, R; ; ; i<num-; i++){ L = lower_bound(x, x+idx, s[i].l) - x; R = lower_bound(x, x+idx, s[i].r) - x - ; update(L,R,s[i].flag,,idx-,); ans+=(sum[]*(s[i+].h-s[i].h)); } printf("Test case #%d\nTotal explored area: %.2lf\n\n", Case++, ans); } ; }
类似知识点 : 利用扫描线求矩形周长并
USACO Overplanting ( 线段树扫描线 )的更多相关文章
- 【Codeforces720D】Slalom 线段树 + 扫描线 (优化DP)
D. Slalom time limit per test:2 seconds memory limit per test:256 megabytes input:standard input out ...
- Codeforces VK CUP 2015 D. Closest Equals(线段树+扫描线)
题目链接:http://codeforces.com/contest/522/problem/D 题目大意: 给你一个长度为n的序列,然后有m次查询,每次查询输入一个区间[li,lj],对于每一个查 ...
- 【POJ-2482】Stars in your window 线段树 + 扫描线
Stars in Your Window Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 11706 Accepted: ...
- HDU 4419 Colourful Rectangle --离散化+线段树扫描线
题意: 有三种颜色的矩形n个,不同颜色的矩形重叠会生成不同的颜色,总共有R,G,B,RG,RB,GB,RGB 7种颜色,问7种颜色每种颜色的面积. 解法: 很容易想到线段树扫描线求矩形面积并,但是如何 ...
- BZOJ-3228 棋盘控制 线段树+扫描线+鬼畜毒瘤
3228: [Sdoi2008]棋盘控制 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 23 Solved: 9 [Submit][Status][D ...
- BZOJ-3225 立方体覆盖 线段树+扫描线+乱搞
看数据范围像是个暴力,而且理论复杂度似乎可行,然后被卡了两个点...然后来了个乱搞的线段树+扫描线.. 3225: [Sdoi2008]立方体覆盖 Time Limit: 2 Sec Memory L ...
- hdu 5091(线段树+扫描线)
上海邀请赛的一道题目,看比赛时很多队伍水过去了,当时还想了好久却没有发现这题有什么水题的性质,原来是道成题. 最近学习了下线段树扫描线才发现确实是挺水的一道题. hdu5091 #include &l ...
- POJ1151+线段树+扫描线
/* 线段树+扫描线+离散化 求多个矩形的面积 */ #include<stdio.h> #include<string.h> #include<stdlib.h> ...
- POJ-1151-Atlantis(线段树+扫描线+离散化)[矩形面积并]
题意:求矩形面积并 分析:使用线段树+扫描线...因为坐标是浮点数的,因此还需要离散化! 把矩形分成两条边,上边和下边,对横轴建树,然后从下到上扫描上去,用col表示该区间有多少个下边,sum代表该区 ...
随机推荐
- java.io.FileNotFoundException: /usr/local/hadoop/logs/fairscheduler-statedump.log(权限不够)解决方案
问题描述:Linux虚拟机内使用hadoop 解决方案: $ su 密码:****** # chown hadoop 文件名 进入超级管理员,为hadoop用户分配该文件的权限. 完美解决:
- xshell简单配置(文件上传和下载)
1.安装lrzsz 1.1直接安装#yum install lrzsz 1.2sudo命令安装#sudo yum install lrzsz -y检查是否安装成功.#rpm -qa |grep lrz ...
- 关于postman
1 Get 1.1 Params 直接显示在url上,即url参数,用&分隔开. springboot中可以用@RequestParam注解获取. 1.2 Headers 1.3 Body 1 ...
- Android View的Adapter
1 Adapter适配的对象是View Adapter通过为View提供指定格式的数据来适配View,让View可以以事先约定好的方式将内容展示给用户. 所以,进行UI设计的关键是搞清楚各个View组 ...
- (Windows)Python第三方库手动安装教程(以lxml库为例)
案例前提:已安装Python 已安装pip 1.进入官网https://www.lfd.uci.edu/~gohlke/pythonlibs/,搜索lxml库,下载到本地(放到Python目录下的Sc ...
- 标准库path源码解读
先看标准库 作用:关于路径的一些实用操作 https://github.com/golang/go/blob/master/src/path/path.go 源码地址 func IsAbs func ...
- 【FAQ】P3. 为什么 torch.cuda.is_available() 是 False
为什么 torch.cuda.is_available() 是 False torch.cuda.is_available(),这个指令的作用是看,你电脑的 GPU 能否被 PyTorch 调用. 如 ...
- Vue 中如何定义全局的变量和常量
Vue 中如何定义全局的变量和常量 我想要定义一个变量, 在项目的任何地方都可以访问到, 不需要每一次使用的时候, 都引入. 尝试1:创建 global.js 并且在其中定义 let a = 10 ...
- SpringMVC_放行静态资源
静态资源到处都是坑!明白原理才能绕过这些坑! web.xml配置servlet中四种路径的区别 在web.xml文件的配置中,四种路径编写方式优先级如下图: 其中b和d都能接收所有请求,仅仅是在优先级 ...
- sklearn逻辑回归库函数直接拟合数据
from sklearn import model_selection from sklearn.linear_model import LogisticRegression from sklearn ...