hdu(1255)——覆盖的面积(线段树求面积交)

原创 2015年07月09日 16:52:54

给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积.

虽说覆盖两次区域的面积,但是这道题实际上就是求矩形的面积交。

膜拜能够想出这种解法的神牛,竟然能把实际的东西用这么抽象的语言表示出来,实在是佩服,现在关于扫描线的题才做了几道,没有对其深刻理解,但是多练总可以理解的,奋斗吧!!ACMer!!我是永远不会服输的。加油!

下面还是附上题解,写的不够详细清楚还请多多见谅。

首先我想说我是看了别人的博客学了思路,然后按照别人的代码来模仿写的。

这里推荐:http://www.cnblogs.com/scau20110726/archive/2013/04/14/3020998.html   http://xuyemin520.is-programmer.com/posts/26000.html(尤其推荐后面那个人写的,代码风格比较适合初学者阅读)

5

1 1 4 2

1 3 3 7

2 1.5 5 4.5

3.5 1.25 7.5 4

6 3 10 7


这是根据第一个样例画的图,我觉得可以跟着代码走一遍,然后就会理解了。

面积交和面积并的区别就在于在线段树中多添加了一个inlen节点,这个的目的是为了保存出现了两次及以上的线段的长度。

然后我们要对线段树的坐标进行离散化,这里我们也是按照x的大小来建树。

主要区别是这里update操作中多了两个函数pushup1,pushup2。它们分别的作用是向上更新只出现过一次的线段的长度以及向上更新出现两次及两次以上的线段的长度。

void pushup1(int v){
    if(tree[v].cover>0) tree[v].len=tree[v].r-tree[v].l;
    else{
        int temp=v<<1;
        tree[v].len=tree[temp].len+tree[temp+1].len;
    }
}
pushup1函数还是和原来一样,当cover>0时,那么len就是整个节点的长度。否则的话,那么就是左右子树中len的和(因为我们不用去管左右子树分别出现过几次,只需要递归求出当前节点的len即可)

void pushup2(int v){
    int temp=v<<1;
    if(tree[v].cover>=2) tree[v].inlen=tree[v].r-tree[v].l;
    else if(tree[v].cover==1){
        tree[v].inlen=tree[temp].len+tree[temp+1].len;
    }
    else tree[v].inlen=tree[temp].inlen+tree[temp+1].inlen;
}
pushup2,函数,当cover>=2时,那么inlen就是当前节点的长度。当cover==1时,这里我想了很久,为什么是左右子树的len加起来就好了呢?后来手动模拟了下,发现如果当前节点cover==1,说明它已经出现过了一次,再加上左右子树的len,就代表的是它加上的肯定是左右子树中出现次数>=1的长度,所以再往上覆盖上去的话,那么就会发现,tree[v].cover就会大于等于2了。

但是另外最后一种情况就是当前v节点cover==0那么它就只能加上左右子树的inlen(也就是出现次数大于等于2的次数的长度

最后我们回溯上去,使父节点tree[1].inlen就是当前区间的高。

代码:

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
#define maxn 2222
double ym[maxn];
struct node{
    double l,r;
    double len,inlen;
    int cover;
}tree[maxn*4];
struct nn{
    double x,y1,y2;
    int flag;
}t[maxn];
bool cmp(nn a,nn b){
    return a.x<b.x;
}
void pushup1(int v){
    if(tree[v].cover>0) tree[v].len=tree[v].r-tree[v].l;
    else{
        int temp=v<<1;
        tree[v].len=tree[temp].len+tree[temp+1].len;
    }
}
void pushup2(int v){
    int temp=v<<1;
    if(tree[v].cover>=2) tree[v].inlen=tree[v].r-tree[v].l;
    else if(tree[v].cover==1){
        tree[v].inlen=tree[temp].len+tree[temp+1].len;
    }
    else tree[v].inlen=tree[temp].inlen+tree[temp+1].inlen;
}
void build(int l,int r,int v){
    tree[v].l=ym[l];
    tree[v].r=ym[r];
    tree[v].len=tree[v].inlen=tree[v].cover=0;
    if(l+1==r)  return ;
    int mid=(l+r)>>1;
    int temp=v<<1;
    build(l,mid,temp);
    build(mid,r,temp+1);
}
void update(int v,struct nn b){
    if(tree[v].l==b.y1&&tree[v].r==b.y2){
        tree[v].cover+=b.flag;
        pushup1(v);
        pushup2(v);
        return ;
    }
    int temp=v<<1;
    if(b.y1>=tree[temp].r) update(temp+1,b);
    else if(b.y2<=tree[temp+1].l) update(temp,b);
    else{
        struct nn y;
        y=b;
        y.y2=tree[temp].r;
        update(temp,y);
        y=b;
        y.y1=tree[temp+1].l;
        update(temp+1,y);
    }
    pushup1(v);
    pushup2(v);
}
int main(){
    int T;
    while(~scanf("%d",&T)){
        int n;
        while(T--){
            memset(ym,0,sizeof(ym));
            memset(tree,0,sizeof(tree));
            memset(t,0,sizeof(t));
            scanf("%d",&n);
            double x1,y1,x2,y2;
            int j=1;
            for(int i=1;i<=n;i++){
                scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
                t[j].flag=1;
                t[j].x=x1;
                t[j].y1=y1;
                t[j].y2=y2;
                ym[j]=y1;
                j++;
                t[j].flag=-1;
                t[j].x=x2;
                t[j].y1=y1;
                t[j].y2=y2;
                ym[j]=y2;
                j++;
            }
            sort(ym+1,ym+j);
            sort(t+1,t+j,cmp);
            build(1,j-1,1);
            update(1,t[1]);
            double sum=0;
            for(int i=2;i<j;i++){<span style="white-space:pre">			</span>//注意这里循环直到j为止
                sum+=(t[i].x-t[i-1].x)*tree[1].inlen;
                update(1,t[i]);
            }
            printf("%.2lf\n",sum);
        }
    }
}




版权声明:本文为博主原创文章,未经博主允许不得转载。

hdu 1255 覆盖的面积(线段树+扫描线——面积交)

Problem Description 给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. Input 输入数据的第一行是一个正整数T(1...

HDU1255-覆盖的面积(线段树+扫描线——面积交)

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

hdu 1255 覆盖的面积 线段树求面积的交 我感觉有点难啊~~第一次写这种类型的

给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. Input 输入数据的第一行是一个正整数T(1...

HDU1255覆盖的面积(线段树+离散化+扫描线)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1542 线段树求面积并升级版 题目大意: 被矩形覆盖过两次的地方的面积 来自大佬的分析:http:/...
  • Rain722
  • Rain722
  • 2017年03月16日 17:04
  • 1116

hdu 1255 覆盖的面积 (线段树 扫描线)

一直想搞线段树的扫描线,这道题算是入门了吧。 这题需要用到

HDU 1255 覆盖的面积 线段树 扫描线

还是先离散化坐标,然后用线段树扫描线 其中sum代表被覆盖过一次的长度,sum2代表被覆盖过2次及以上的长度。 然后注意pushup操作比较麻烦。 /* ID: sdj22251 PROG: s...

HDU - 1255 覆盖的面积(线段树 扫描线)

题目大意:中文题解题思路:记录区间被cover的次数,区间的被cover1次的长度len,区间被cover2次或者2次以上的长度twice 所要求的覆盖面积,就是求被cover两次或者两次以上的长度...

HDU 1255 覆盖的面积 线段树

题意:给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. 题解:和 poj1151 类似,不过要求的是面积的交,同样是先离散化然后枚举x坐标。此题更新时求y方向的“合法长度”相对于 po...
  • Tsaid
  • Tsaid
  • 2011年08月22日 13:04
  • 1179

线段树扫描线(覆盖两次以上的面积和)hdu1255

为什么加边的那条边是-1会有影响 思路:

hdu 1255 覆盖的面积 线段树+离散化+扫描线

题意:给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. 分析:这题跟poj 1151有点相似,只不过多了至少覆盖两次而已。那我们就在原来的基础上改进一下。 一开始的操作,像离散化之类...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:hdu(1255)——覆盖的面积(线段树求面积交)
举报原因:
原因补充:

(最多只允许输入30个字)