poj1151Atlantis 扫描线法,暴力和线段树优化

解法:
1.离散化y的坐标,通过二分寻找
2.将x坐标排序,并保存为(x1,y1,y2,1),(x2,y1,y2,-1);
对于矩形左边界+1,对于矩形右边界-1。
3.从小到大扫描每一个x,并且维护当前y轴上的有效长度
ans+=两个x的坐标差*当前y轴上的有效长度

线段树优化:线段树维护的不是点,而是两个点之间的区间

暴力代码:

#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#include<cstdio>
using namespace std;

const int N = 10005;
struct Seg{
    double x,y1,y2;
    int k;
    bool operator < (const Seg &t)const {
        return x<t.x;
    }
}seg[2*N];
int idx;
int b[N*2];
Seg make_seg(double x,double y1,double y2,int k){
    Seg cur;
    cur.x = x,cur.y1 = y1,cur.y2 = y2,cur.k = k;
    return cur;
}

vector<double> alls;
int n;

int find(double x){
    int l = 0,r = alls.size()-1;
    while(l<r){
        int mid = l+r>>1;
        if(alls[mid] >= x) r = mid;
        else l = mid + 1;
    }
    return l;
}

int main(){
    int i,j,k;
    int num = 0;
    while(cin>>n,n){
        memset(b,0,sizeof b);
        alls.clear();
        memset(seg,0,sizeof seg);
        for(i = 1;i<=n;i++){
            double x1,x2,y1,y2;
            cin>>x1>>y1>>x2>>y2;
            seg[++idx] = make_seg(x1,y1,y2,1);
            seg[++idx] = make_seg(x2,y1,y2,-1);
            alls.push_back(y1);
            alls.push_back(y2);
        }
        sort(seg+1,seg+1+idx);
        
        sort(alls.begin(),alls.end());
        alls.erase(unique(alls.begin(),alls.end()),alls.end());
        double ans = 0;
        for(i = 1;i<idx;i++){
            for(j = i;seg[j].x == seg[j+1].x;j++,i++){
                int l = find(seg[j].y1);
                int r = find(seg[j].y2);
                int v = seg[j].k;
                for(k = l;k<r;k++){
                    b[k] += v;
                }
            }
            int l = find(seg[j].y1);
            int r = find(seg[j].y2);
            int v = seg[j].k;
            for(k = l;k<r;k++){
                b[k] += v;
            }                                                                                   
            double res = 0;
            for(j = 0;j<alls.size();j++){
                if(b[j] > 0){
                    res += alls[j+1]-alls[j];
                }
            }
            ans += (seg[i+1].x-seg[i].x)*res;
        }
        num++;
        printf("Test case #%d\nTotal explored area: %0.2lf\n\n",num,ans);
    }
    return 0;
}

线段树优化:

#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#include<cstdio>
using namespace std;

const int N = 100005;
struct Seg{
    double x,y1,y2;
    int k;
    bool operator < (const Seg &t)const {
        return x<t.x;
    }
}seg[2*N];
int idx;
int b[N*2];
Seg make_seg(double x,double y1,double y2,int k){
    Seg cur;
    cur.x = x,cur.y1 = y1,cur.y2 = y2,cur.k = k;
    return cur;
}

struct Node{
    int l,r;
    double len;//当前区间的有效长度
    //区间总长度为alls[r]-alls[l-1]
    int v;
}tr[N*4];

vector<double> alls;
int n;

void build(int u,int l,int r){
    tr[u].l = l,tr[u].r = r;
    if(l != r){
        int mid = l + r>>1;
        build(2*u,l,mid);
        build(2*u+1,mid+1,r);
    }
}

void pushup(int u){
    if(tr[u].v) tr[u].len = (alls[tr[u].r]-alls[tr[u].l-1]);
    else if(tr[u].l != tr[u].r) tr[u].len = tr[2*u].len + tr[2*u+1].len;
    else    tr[u].len = 0;
}

void update(int u,int l,int r,int k){
    
    if(l<=tr[u].l && tr[u].r<=r){
        tr[u].v += k;
        pushup(u);
    }else{
        
        int mid = tr[u].l + tr[u].r >>1;
        if(l<=mid)
            update(u*2,l,r,k);
        if(r>mid)
            update(u*2+1,l,r,k);
        pushup(u);
    }
}
int find(double x){
    int l = 0,r = alls.size()-1;
    while(l<r){
        int mid = l+r>>1;
        if(alls[mid] >= x) r = mid;
        else l = mid + 1;
    }
    return l;
}
int main(){
    int i,j,k;
    int num = 0;
    while(cin>>n,n){
        memset(b,0,sizeof b);
        alls.clear();
        memset(seg,0,sizeof seg);
        for(i = 1;i<=n;i++){
            double x1,x2,y1,y2;
            cin>>x1>>y1>>x2>>y2;
            seg[++idx] = make_seg(x1,y1,y2,1);
            seg[++idx] = make_seg(x2,y1,y2,-1);
            alls.push_back(y1);
            alls.push_back(y2);
        }
        sort(seg+1,seg+1+idx);
        
        sort(alls.begin(),alls.end());
        alls.erase(unique(alls.begin(),alls.end()),alls.end());
        double ans = 0;
        build(1,1,alls.size()-1);
        for(i = 1;i<=idx;i++){
            if(i>1) ans += tr[1].len * (seg[i].x - seg[i-1].x);
            update(1,find(seg[i].y1)+1,find(seg[i].y2),seg[i].k);
        }
        num++;
        printf("Test case #%d\nTotal explored area: %0.2lf\n\n",num,ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值