hdu 1542 Atlantis 线段树矩形面积并+离散化

题目:http://acm.hdu.edu.cn/showproblem.php?pid=1542

题意:给一些矩形,可能会有重叠,求总的矩形面积

我是看了胡浩的那篇文章,学习一下。

思路:浮点数先要离散化;然后把矩形分成两条边,上边和下边,对横轴建树,然后从下到上扫描上去,用cnt表示该区间下边比上边多几个,sum代表该区间内被覆盖的线段的长度总和
这里线段树的一个结点并非是线段的一个端点,而是该端点和下一个端点间的线段,所以题目中r+1,r-1的地方可以自己好好的琢磨一下
线段树操作:update:区间增减 query:直接取根节点的值

分析:因为线段树每个节点表示的是一个边长,而不是一些点的区间,比如说对于下边【0,1】区间和上边【1,2】区间,如果在更新的时候r不减1,那么1这个点就会被合并,变成【0,0】和【2,2】的边长和,所以在更新的时候r-1.这样的话在求边长总和sum的时候再把1加上去,这样就解决这个问题了。如果读不懂,可以看一下这个图上的解释,在理解一下。http://blog.csdn.net/cen5bin/article/details/7833089

离散化横坐标,对横坐标建树,由于在计算横坐标的时候会去重,得到不同的横坐标k个,因为横坐标数组从0开始,所以要k-1。在更新节点的时候,由于r-1,所以也要对应k-1

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int N=205;
int cnt[N<<2];
double sum[N<<2],X[N];
struct edge
{
    double l,r,h;
    int s;
    edge(){}
    edge(double a,double b,double c,int d):l(a),r(b),h(c),s(d){}
    bool operator<(const edge &cmp)const{
        return h<cmp.h;
    }
}e[N];
void pushUP(int l,int r,int rt)
{
    if(cnt[rt])sum[rt]=X[r+1]-X[l];  //如果是整段都有边,总边长直接左右两个端点之差,这里r+1,是因为在更新的时候r减了1
    else if(l==r)sum[rt]=0; //如果两个端点没有覆盖边,那么这个边长不加了总长里。
    else sum[rt]=sum[rt<<1]+sum[rt<<1|1]; //否则从子节点得到边长
}
void update(int a,int b,int c,int l,int r,int rt)
{
    if(a<=l&&r<=b){
        cnt[rt]+=c;
        pushUP(l,r,rt);
        return;
    }
    int m=(l+r)>>1;
    if(a<=m)update(a,b,c,lson);
    if(m<b)update(a,b,c,rson);
    pushUP(l,r,rt);
}
int Bin(double key,int n,double X[])
{
    int l=0,r=n;
    while(l<=r){
        int m=(l+r)>>1;
        if(X[m]==key)return m;
        if(X[m]<key)l=m+1;
        else r=m-1;
    }
    return -1;
}
int main()
{
    int n,cas=0;
    //freopen("f.txt","r",stdin);
    while(~scanf("%d",&n)&&n){
        int m=0;
        while(n--){
            double a,b,c,d;
            scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
            X[m]=a;
            e[m++]=edge(a,c,b,1);
            X[m]=c;
            e[m++]=edge(a,c,d,-1);
        }
        sort(X,X+m);
        sort(e,e+m);
        int k=1;
        for(int i=1;i<m;i++){
            if(X[i]!=X[i-1])X[k++]=X[i];
        }
        k--;  //注意这里
        memset(cnt,0,sizeof(cnt));
        memset(sum,0,sizeof(sum));
        double ans=0;
        for(int i=0;i<m-1;i++){
            int l=Bin(e[i].l,k,X);
            int r=Bin(e[i].r,k,X)-1;
            if(l<=r)update(l,r,e[i].s,0,k-1,1); //k和r都减一的原因是一样的。
            ans+=sum[1]*(e[i+1].h-e[i].h);
        }
        printf("Test case #%d\nTotal explored area: %.2lf\n\n",++cas , ans);
    }
    return 0;
}


评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值