Poj P1151 Atlantis___线段树+离散化+扫描线

题目大意:

N(x1,y1)(x2,y2) 给 出 一 个 平 面 内 N 个 矩 形 的 左 下 角 顶 点 ( x 1 , y 1 ) 及 右 上 角 顶 点 ( x 2 , y 2 )
问 它 们 在 平 面 中 占 的 总 面 积 是 多 少 。

1N100 1 ≤ N ≤ 100
0<=x1<x2<=100000;0<=y1<y2<=100000 0 <= x 1 < x 2 <= 100000 ; 0 <= y 1 < y 2 <= 100000

分析:

可以采用扫描线 O(n2) O ( n 2 ) 的实现,
也可以通过线段树对扫描线进行优化,
达到 O(nlogn) O ( n l o g n )
扫描线的几篇详细blog
https://blog.csdn.net/otowa/article/details/50695401
这题还要注意一下对 xi x i 进行离散

代码:

#include<algorithm>  
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define N 205   
#define eps 1e-6

using namespace std;  

struct Node {  
    double l, r, h;  
    int add;    
}c[N];  
struct Note {  
    int l, r, p;  
    double sum;  
}a[5 * N];
double x[N];

bool cmp(Node aa, Node bb) {  
    return aa.h < bb.h;  
}  

void Build_tree(int G, int l, int r) {  
    a[G].l = l, a[G].r = r;  
    a[G].sum = a[G].p = 0;  
    if (l == r)  return;  
    int mid = (l + r) >> 1;  
    Build_tree(G * 2, l, mid);  
    Build_tree(G * 2 + 1, mid + 1, r);  
}  

int Get_id(double num, int l, int r) {  
    while (l <= r) {  
        int mid = (l + r) >> 1;
        if (fabs(x[mid] - num) <= eps) return mid;    
        if (x[mid] < num) l = mid + 1;  
                     else r = mid - 1;  
    }  
    return l;
}  

double Get_sum(int G) {   
    if (a[G].p) return x[a[G].r + 1] - x[a[G].l];    
    return a[G * 2].sum + a[G * 2 + 1].sum;  
}  

void Insert_tree(int G, int x1, int x2, int add) {  
    if (a[G].l == x1 && a[G].r == x2) {  
        a[G].p += add;  
        a[G].sum = Get_sum(G);
        return;  
    }  
    int mid = (a[G].l + a[G].r) >> 1;  
    if (x2 <= mid) Insert_tree(G * 2, x1, x2, add);  
              else if (x1 > mid) Insert_tree(G * 2 + 1, x1, x2, add);  
                            else {  
                                 Insert_tree(G * 2, x1, mid, add);  
                                 Insert_tree(G * 2 + 1, mid + 1, x2, add);  
                            }  
    a[G].sum = Get_sum(G); 
}  
int main() { 
    double x1, y1, x2, y2, ans;
    int n, tot, Case = 0;  
    while (~scanf("%d", &n) && n) {  
            tot = 0;  
            for (int i = 1; i <= n; i++) {  
                 scanf("%lf %lf %lf %lf", &x1, &y1, &x2, &y2);  
                 x[++tot] = x1, c[tot].l = x1, c[tot].r = x2, c[tot].h = y1, c[tot].add = 1;
                 x[++tot] = x2, c[tot].l = x1, c[tot].r = x2, c[tot].h = y2, c[tot].add = -1;
           }  
           sort(c + 1, c + tot + 1, cmp);  
           sort(x + 1, x + tot + 1); 
           int cnt = 1;  
           for (int i = 2; i <= tot; i++)   
                if (x[i] != x[i - 1]) x[++cnt] = x[i];   
           ans = 0;  
           Build_tree(1, 1, cnt - 1);  
           for (int i = 1; i < tot; i++)  {
                int x1 = Get_id(c[i].l, 1, cnt);  
                int x2 = Get_id(c[i].r, 1, cnt) - 1;  
                if (x1 <= x2) Insert_tree(1, x1, x2, c[i].add);  
                ans += (c[i + 1].h - c[i].h) * a[1].sum;  
           }  
           printf("Test case #%d\n", ++Case);  
           printf("Total explored area: %.2f\n\n", ans);  
    }  
    return 0;  
}  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值