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

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

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

膜拜能够想出这种解法的神牛,竟然能把实际的东西用这么抽象的语言表示出来,实在是佩服,现在关于扫描线的题才做了几道,没有对其深刻理解,但是多练总可以理解的,奋斗吧!!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);
        }
    }
}

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

时间: 2024-10-13 18:00:56

hdu(1255)——覆盖的面积(线段树求面积交)的相关文章

HDU 1264 Counting Squares(线段树求面积的并)

Counting Squares Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 1885    Accepted Submission(s): 946 Problem Description Your input is a series of rectangles, one per line. Each rectangle is sp

HDU-1255-覆盖的面积-线段树求面积并(模板)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1255 好吧,这题和HDU1542几乎完全一样,链接:http://blog.csdn.net/wlxsq/article/details/47254571我有详细讲: 这个题目唯一的不同就是这是个求重合的面积,而HDU1542是求并面积,如果明白了1542题目的原理,我想很轻松的就可以搞定这个题目,只要将cover>0改成cover>1就可以求出覆盖面积了,我这里就不在赘述了:代码我再贴一下 #i

hdu 1542 Atlantis 线段树求面积并,,,尼玛数据真坑人,数组千万不能开小!

Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 7815    Accepted Submission(s): 3420 Problem Description There are several ancient Greek texts that contain descriptions of the fabled i

HDU 1828 / POJ 1177 Picture --线段树求矩形周长并

题意:给n个矩形,求矩形周长并 解法:跟求矩形面积并差不多,不过线段树节点记录的为: len: 此区间线段长度 cover: 此区间是否被整个覆盖 lmark,rmark: 此区间左右端点是否被覆盖 num: 此区间分离开的线段的条数 重点在转移的地方,不难理解. 代码: #include <iostream> #include <cmath> #include <iostream> #include <cstdio> #include <cstrin

poj-1151-Atlantis-线段树求面积并

很裸的线段树求面积并. 坐标需要离散化一下. #include<stdio.h> #include<iostream> #include<stdlib.h> #include<string.h> #include<algorithm> #include<vector> #include<math.h> #include<map> #pragma comment(linker, "/STACK:1024

hdu 1255 覆盖的面积 线段树扫描线求重叠面积

稀里糊涂打完了没想到1A了,心情还是很舒畅的,c和c++的四舍五入还是四舍六入遇积进位遇偶舍,我感觉很混乱啊,这道题我输出的答案是7.62,也就是遇偶舍了,可是我就手动处理一下进位问题,发现0.005 系统自动进位0.01了,尼玛啊,我一下子就混乱了,不是遇偶舍么,0也是偶数啊,怎么就进位了呢.最后我就不手动处理进位问题了,直接0.2lf%,虽然我输出的结果是7.62,但是提交也过了 这道题和poj1151,hdu1542差不多,扫描线详细讲解http://blog.csdn.net/young

hdu 1255 覆盖的面积(线段树&amp;扫描线&amp;重复面积)

覆盖的面积 Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 3375    Accepted Submission(s): 1645 Problem Description 给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. Input 输入数据的第一行是一个正整数T(1<=T<=100),代表测试数据的数量.每个测试数

HDU 1255 覆盖的面积 (扫描线 线段树 离散化)

题目链接 题意:中文题意. 分析:纯手敲,与上一道题目很相似,但是刚开始我以为只是把cnt>=0改成cnt>=2就行了,. 但是后来发现当当前加入的线段的范围之前 还有线段的时候就不行了,因为虽然现在都不等于 2,但是之前的那个线段加上现在的已经覆盖2次了. 1 #include <iostream> 2 #include <cstdio> 3 #include <vector> 4 #include <cstring> 5 #include &

HDU 1542 Atlantis (线段树求矩阵覆盖面积)

题意:给你n个矩阵求覆盖面积. 思路:看了别人的结题报告 给定一个矩形的左下角坐标和右上角坐标分别为:(x1,y1).(x2,y2),对这样的一个矩形,我们构造两条线段,一条定位在x1,它在y坐标的区间是[y1,y2],并且给定一个cover域值为1:另一条线段定位在x2,区间一样是[y1,y2],给定它一个cover值为-1.根据这样的方法对每个矩形都构造两个线段,最后将所有的线段根据所定位的x从左到右进行排序 #include <iostream> #include <stdio.h