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

题目分析

上次做了一道只用计算覆盖一次的面积,这次需要计算覆盖2次的面积,其实就是在上面的基础上加一点东西,sum1[]表示覆盖一次的长度,sum2[]覆盖2次的长度,具体怎么操作看pushup函数即可,写的非常清楚。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define mid (L+R)/2
#define lson o<<1, L, mid
#define rson o<<1|1, mid+1, R
const int maxn = 2005;

double pos[maxn<<2];
double sum1[maxn<<2], sum2[maxn<<2];  //sum1表示覆盖一次的长度,sum2表示覆盖2次的长度
int flag[maxn<<2];

struct Edge{
    double l, r, h;
    int f;
    Edge(){}
    Edge(double a, double b, double c, int d):l(a), r(b), h(c), f(d){}
    bool operator < (const Edge& e)const{
        return h < e.h;
    }
}line[maxn];

void pushup(int o,int L,int R){   //这里代码已经写得很清楚了
    if(flag[o]) sum1[o] = pos[R+1] - pos[L];    
    else if(L == R) sum1[o] = 0;
    else sum1[o] = sum1[o<<1] + sum1[o<<1|1];

    if(flag[o] > 1) sum2[o] = pos[R+1] - pos[L];
    else if(L == R) sum2[o] = 0;
    else if(flag[o] == 1) sum2[o] = sum1[o<<1] + sum1[o<<1|1];
    else sum2[o] = sum2[o<<1] + sum2[o<<1|1];
}

void update(int o,int L,int R,int l,int r,int val){ //更新
    if(l <= L && R <= r){
        flag[o] += val;
        pushup(o, L, R);
        return;
    }
    if(l <= mid) update(lson, l, r, val);
    if(r > mid) update(rson, l, r, val);
    pushup(o, L, R);
}

int BS(double k, double a[], int len){  //二分查找
    int L = 0, R = len-1;
    while(L <= R){
        if(a[mid] == k) return mid;
        else if(a[mid] < k) L = mid+1;
        else R = mid-1;
    }
    return -1;
}

int main(){
    int T, n;
    scanf("%d", &T);
    while(T--){
        memset(sum1, 0, sizeof(sum1));
        memset(sum2, 0, sizeof(sum2));
        memset(flag, 0, sizeof(flag));
        memset(pos, 0, sizeof(pos));
        double x1, y1, x2, y2;
        scanf("%d", &n);
        int k = 0;
        for(int i = 0; i < n; i++){
            scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
            pos[k] = x1;
            line[k++] = Edge(x1, x2, y1, 1);
            pos[k] = x2;
            line[k++] = Edge(x1, x2, y2, -1);
        }
        sort(pos, pos+k);
        sort(line, line+k);
        int m = 1;
        for(int i = 1; i < k; i++)
            if(pos[i] != pos[i-1]) pos[m++] = pos[i];
        double ans = 0;
        for(int i = 0; i < k-1; i++){
            int l = BS(line[i].l, pos, m);
            int r = BS(line[i].r, pos, m)-1;
            update(1, 0, k-1, l, r, line[i].f);
            ans += sum2[1]*(line[i+1].h - line[i].h);
        }
        printf("%.2lf\n", ans);
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值