您的位置:首页 > 其它

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(很详细,是求的周长);

不想讲了,其实会求周长了,就肯定会求面积了;

先看下这个:

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  poj 1151 1177 线段树