HDU 1542 Atlantis(线段树+离散化+扫描线)

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

这个题目之前用线段切割方法做过,觉得做法经典,但是如果数据量大的话线段切割就力不从心了,后来尝试用线段树来解决

线段树方法也非常经典,由于开始有些细节没理解,用线段树一直都没能过,今天终于过了!

按照y坐标进行离散化解,之后不断插入竖线,用一颗线段树维护就行了

之前一直没能理解的是为什么标记是左边线段课右边线段就能判断当前面积能否是处在矩形内部

现在明白了,其实不难理解(但也不好说清楚),只是当时懒不愿意在纸上画画,这个方法仔细

读读代码,仔细在纸上画一遍就都明白了!


#include <iostream>
#include <string.h>
#include <algorithm>
#include <stdio.h>
#include <set>
#include <vector>
#include <map>
using namespace std;
#define maxn 20000
struct line{
    double x,y1,y2;
    int flag;
    line(){}
    line(double _x,double _y1,double _y2,int f):x(_x),y1(_y1),y2(_y2),flag(f){}
    bool operator < (const line &a) const{
        return x < a.x;
    }
};
struct point{
    int l,r,flag;
    double total;
}po[maxn*4];
int n;
vector<double> y;
vector<line>li;
map<double ,int> m;
int build_tree(int root,int l,int r){
    po[root].l=l,po[root].r=r;
    po[root].flag=0,po[root].total=0;
    if(l+1 == r) return 0;
    int mid=(l+r)>>1;
    build_tree(root<<1,l,mid);
    build_tree((root<<1)+1,mid,r);
    return 0;
}
int insert(int root,int l,int r,int flag){
    if(po[root].l+1 == po[root].r){
        po[root].flag+=flag;
        if(po[root].flag==0) po[root].total=0;
        else po[root].total=y[r]-y[l];
    }
    else{
        int mid=(po[root].l+po[root].r)>>1;
        if(l>=mid) insert((root<<1|1),l,r,flag);
        else if(r<=mid) insert(root<<1,l,r,flag);
        else insert(root<<1,l,mid,flag),insert((root<<1|1),mid,r,flag);
        po[root].total=po[root<<1].total+po[(root<<1|1)].total;
    }
    return 0;
}
int main(){
    int i,j,k,cas=0;
    double x1,y1,x2,y2,ans;
    while(scanf("%d",&n),n){
        m.clear();y.clear();li.clear();
        for(i=0;i<n;i++){
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            li.push_back(line(x1,y1,y2,-1));
            li.push_back(line(x2,y1,y2,1));
            y.push_back(y1),y.push_back(y2);
        }
        sort(li.begin(),li.end());
        sort(y.begin(),y.end());
        y.erase(unique(y.begin(),y.end()),y.end());
        for(i=0;i<y.size();i++) m[y[i]]=i;
        build_tree(1,0,y.size()-1);
        ans=0;
        for(i=0;i<li.size();i++){
            if(i!=0) ans+=(li[i].x-li[i-1].x)*po[1].total;
            insert(1,m[li[i].y1],m[li[i].y2],li[i].flag);
        }
        printf("Test case #%d\nTotal explored area: %.2f\n\n",++cas,ans);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值