poj 1151 Atlantis(多矩形面积) + poj 1177Picture(多矩形周长) 线段树进阶
2017-04-27 16:43
447 查看
题意:平面内有很多矩形,求它们组成的图形的总面积;
题解:
先将清楚一个东西,我用的扫描线是一根平行y轴的线,从左到右扫描(你也可以用一根横向的扫描线从下到上扫描),离散化就是把这跟线上的点hash一下;
1: 什么是离散化,其实很简单不要被这三个陌生的字给吓到了,这题我用的是将在y轴的点线离散化 ;
比如有y轴上有4个坐标分别是1, 30, 1000, 100000;按照一般的建树要从 1~100000;
离散化意思就是将于他们hash一下1还是1,30看成是2,1000看成3, 100000看成4,然后建树就变成了1~4;
巨大的节省了时间和空间;
poj 1151求面积这题有坐标是小数,你只能离散化建树;
下面再来看看扫描线:http://www.cnblogs.com/Booble/archive/2010/10/10/1847163.html(很详细,是求的周长);
不想讲了,其实会求周长了,就肯定会求面积了;
先看下这个:
注意:还有一个建树问题,别那样建,要这样建,哈哈哈!
还有就是当要插入或删除的线段x值相等时,要先插入再删除;因为如果两个矩形相邻,重合的那条边是不计入总周长的;
代码:
求面积的话,就只要更新测度m了;
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define lson k<<1, l, mid, ff
#define rson k<<1|1, mid, r, ff
const int MAXN = 102;
struct Lines {
float x, y1, y2;
int flag;
Lines(float a, float b, float c, int d):x(a),y1(b),y2(c),flag(d){}
Lines(){}
} lines[2*MAXN];
struct TreeLines {
int cover;
float m;
} tree[8*MAXN];
float yID[2*MAXN];
void updataM(int k, int l, int r) {
if (tree[k].cover > 0)
tree[k].m = yID[r]-yID[l];
else {
if (r-l == 1) tree[k].m = 0;
else tree[k].m = tree[k<<1].m + tree[k<<1|1].m;
}
}
void query(float li, float ri, int k, int l, int r, int ff) {
if (li <= yID[l] && ri >= yID[r]) {
tree[k].cover += ff;
}
else if (r-l > 1){
int mid = (l+r)/2;
if (li < yID[mid]) query(li, ri, lson);
if (ri > yID[mid]) query(li, ri, rson);
}
updataM(k, l, r);
}
int cmp(Lines aa, Lines bb) {
if (aa.x == bb.x)
return aa.flag > bb.flag;
else return aa.x < bb.x;
}
int main() {
float x1, x2, y1, y2;
int j, T, tt = 1;
while(scanf("%d", &T) && T) {
memset(tree, 0, sizeof(tree));
j = 1;
while (T--) {
scanf("%f%f%f%f", &x1, &y1, &x2, &y2);
lines[j] = Lines(x1, y1, y2, 1);
yID[j++] = y1;
lines[j] = Lines(x2, y1, y2, -1);
yID[j++] = y2;
}
sort(yID+1, yID+j);
int k = 1;
for(int i = 1; i < j; i++) {
yID[k++] = yID[i];
while (yID[i] == yID[i+1]) i++;
}
sort(lines+1, lines+j, cmp);
float preM = 0;
double res = 0;
for(int i = 1; i < j; i++) {
query(lines[i].y1, lines[i].y2, 1, 1, k-1, lines[i].flag);
if (i > 1) res += preM*(lines[i].x-lines[i-1].x);
preM = tree[1].m;
}
printf("Test case #%d\nTotal explored area: %.2f\n\n", tt++, res);
}
return 0;
}
题解:
先将清楚一个东西,我用的扫描线是一根平行y轴的线,从左到右扫描(你也可以用一根横向的扫描线从下到上扫描),离散化就是把这跟线上的点hash一下;
1: 什么是离散化,其实很简单不要被这三个陌生的字给吓到了,这题我用的是将在y轴的点线离散化 ;
比如有y轴上有4个坐标分别是1, 30, 1000, 100000;按照一般的建树要从 1~100000;
离散化意思就是将于他们hash一下1还是1,30看成是2,1000看成3, 100000看成4,然后建树就变成了1~4;
巨大的节省了时间和空间;
poj 1151求面积这题有坐标是小数,你只能离散化建树;
下面再来看看扫描线:http://www.cnblogs.com/Booble/archive/2010/10/10/1847163.html(很详细,是求的周长);
不想讲了,其实会求周长了,就肯定会求面积了;
先看下这个:
struct TreeLines { int nLines;//这个区间里包括的线段的数量 int lLines;//这个区间左端点是否被覆盖; int rLines;//右端点是否被覆盖; //上面两个没其他用,就是辅助对nLines的计算的,先别想太多; int cover;//当前区间被覆盖的次数,其实也是用来辅助计算的 int m;//测度(意思就是这个区间里被覆盖线段的总和) } tree[8*MAXN];
注意:还有一个建树问题,别那样建,要这样建,哈哈哈!
还有就是当要插入或删除的线段x值相等时,要先插入再删除;因为如果两个矩形相邻,重合的那条边是不计入总周长的;
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; #define lson k<<1, l, mid, ff #define rson k<<1|1, mid, r, ff const int MAXN = 5002; //要插入或删除的线段; struct Lines { int x, y1, y2, flag;//flag=1表示要插入的线段,-1表示要删除的; Lines(int a, int b, int c, int d):x(a),y1(b),y2(c),flag(d){} Lines(){} } lines[2*MAXN]; //扫描线(线段树) struct TreeLines { int lLines, rLines, cover, m, nLines; } tree[8*MAXN]; int yID[2*MAXN];//hash //更新m void updataM(int k, int l, int r) { if (tree[k].cover > 0) tree[k].m = yID[r]-yID[l]; else { if (r-l == 1) tree[k].m = 0; else tree[k].m = tree[k<<1].m + tree[k<<1|1].m; } } //更新nLines,实际上是3个变量一起更新 void updataN(int k, int l, int r) { if (tree[k].cover > 0) tree[k].lLines = tree[k].nLines = tree[k].rLines = 1; else { if (r-l == 1) tree[k].lLines = tree[k].nLines = tree[k].rLines = 0; else { int ll = k<<1, rr = k<<1|1; tree[k].lLines = tree[ll].lLines; tree[k].rLines = tree[rr].rLines; tree[k].nLines = tree[ll].nLines+tree[rr].nLines-(tree[ll].rLines&tree[rr].lLines); } } } void query(int li, int ri, int k, int l, int r, int ff) { if (li <= yID[l] && ri >= yID[r]) { tree[k].cover += ff; } else if (r-l > 1){//我说是这样建树 int mid = (l+r)/2; if (li < yID[mid]) query(li, ri, lson); if (ri > yID[mid]) query(li, ri, rson); } //这里比较重要是回归的时候更新值;(第一次做这样的) updataM(k, l, r); updataN(k, l, r); } int cmp(Lines aa, Lines bb) { if (aa.x == bb.x) return aa.flag > bb.flag;//这里注意,先要插入,在删除 else return aa.x < bb.x; } int main() { int x1, x2, y1, y2, j = 1, T; scanf("%d", &T); memset(tree, 0, sizeof(tree)); while (T--) { scanf("%d%d%d%d", &x1, &y1, &x2, &y2); lines[j] = Lines(x1, y1, y2, 1); yID[j++] = y1; lines[j] = Lines(x2, y1, y2, -1); yID[j++] = y2; } sort(yID+1, yID+j); int k = 1; for(int i = 1; i < j; i++) {//删除重复节点 yID[k++] = yID[i]; while (yID[i] == yID[i+1]) i++; } sort(lines+1, lines+j, cmp); int res = 0, preN, preM = 0; for(int i = 1; i < j; i++) {//一个区间,一个区间的求; query(lines[i].y1, lines[i].y2, 1, 1, k-1, lines[i].flag); if (i > 1) res += preN*2*(lines[i].x-lines[i-1].x); res += abs(preM-tree[1].m); preM = tree[1].m; preN = tree[1].nLines; } printf("%d\n", res); return 0; }
求面积的话,就只要更新测度m了;
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define lson k<<1, l, mid, ff
#define rson k<<1|1, mid, r, ff
const int MAXN = 102;
struct Lines {
float x, y1, y2;
int flag;
Lines(float a, float b, float c, int d):x(a),y1(b),y2(c),flag(d){}
Lines(){}
} lines[2*MAXN];
struct TreeLines {
int cover;
float m;
} tree[8*MAXN];
float yID[2*MAXN];
void updataM(int k, int l, int r) {
if (tree[k].cover > 0)
tree[k].m = yID[r]-yID[l];
else {
if (r-l == 1) tree[k].m = 0;
else tree[k].m = tree[k<<1].m + tree[k<<1|1].m;
}
}
void query(float li, float ri, int k, int l, int r, int ff) {
if (li <= yID[l] && ri >= yID[r]) {
tree[k].cover += ff;
}
else if (r-l > 1){
int mid = (l+r)/2;
if (li < yID[mid]) query(li, ri, lson);
if (ri > yID[mid]) query(li, ri, rson);
}
updataM(k, l, r);
}
int cmp(Lines aa, Lines bb) {
if (aa.x == bb.x)
return aa.flag > bb.flag;
else return aa.x < bb.x;
}
int main() {
float x1, x2, y1, y2;
int j, T, tt = 1;
while(scanf("%d", &T) && T) {
memset(tree, 0, sizeof(tree));
j = 1;
while (T--) {
scanf("%f%f%f%f", &x1, &y1, &x2, &y2);
lines[j] = Lines(x1, y1, y2, 1);
yID[j++] = y1;
lines[j] = Lines(x2, y1, y2, -1);
yID[j++] = y2;
}
sort(yID+1, yID+j);
int k = 1;
for(int i = 1; i < j; i++) {
yID[k++] = yID[i];
while (yID[i] == yID[i+1]) i++;
}
sort(lines+1, lines+j, cmp);
float preM = 0;
double res = 0;
for(int i = 1; i < j; i++) {
query(lines[i].y1, lines[i].y2, 1, 1, k-1, lines[i].flag);
if (i > 1) res += preM*(lines[i].x-lines[i-1].x);
preM = tree[1].m;
}
printf("Test case #%d\nTotal explored area: %.2f\n\n", tt++, res);
}
return 0;
}
相关文章推荐
- zoj 1128 || poj 1151 Atlantis(线段树求矩形面积并)
- POJ 1151 Atlantis(线段树+扫描线+坐标离散求矩形面积并)
- POJ 1151 Atlantis(扫描线 + 线段树 矩形面积的并)
- POJ 1151 Atlantis 线段树/矩形面积并
- POJ-1151-Atlantis(线段树+扫描线+离散化)[矩形面积并]
- poj 1151 Atlantis (离散化 + 扫描线 + 线段树 矩形面积并)
- POJ 1151 / HDU 1542 Atlantis 线段树求矩形面积并
- POJ 1151 Atlantis 矩形面积求交/线段树扫描线
- hdu 1542&&poj 1151 Atlantis[线段树+扫描线求矩形面积的并]
- 【线段树 + 离散化 + 扫描线】poj 1151 Atlantis 矩形面积并
- poj 1151 Atlantis / hdu 1542 线段树扫描线 矩形面积并
- POJ 1151 Atlantis (线段树+扫描线 求矩形面积并)
- POJ 1151Atlantis 矩形面积并[线段树 离散化 扫描线]
- POJ 1151 Atlantis (线段树求矩形面积并)
- poj 1151-Atlantis线段树求矩形面积并解题报告
- POJ 1151 Atlantis 线段树求矩形面积并 方法详解
- hdu 1542 & poj 1151 Atlantis 线段树扫描线求矩形面积并
- POJ 1151 / HDU 1542 Atlantis 线段树求矩形面积并
- poj 1151 Atlantis 求矩形面积并
- POJ 1151 Atlantis(线段树离散化求面积并)(C++)