poj 1151 Atlantis(多矩形面积) + poj 1177Picture(多矩形周长) 线段树进阶

来源:互联网 发布:淘宝代销怎么关联宝贝 编辑:程序博客网 时间:2024/06/06 06:37

题意:平面内有很多矩形,求它们组成的图形的总面积;

题解:

先将清楚一个东西,我用的扫描线是一根平行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, ffconst 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//更新mvoid 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, ffconst 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;}



0 0