hdu 1255 覆盖的面积 离散化+线段树

http://acm.hdu.edu.cn/showproblem.php?pid=1255 

 

用cnt记录覆盖几次,once与twice表示覆盖一次与两次时的长度

离散后二分查找,开始直接用的map…… 此外代码各种挫……然后就超时了,虽然感觉超时的问题应该不在离散这,但二分还是比map快……

 

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define LL(x) (x << 1)
#define RR(x) (x << 1 | 1)
using namespace std;
const int maxn= 2010;
const double eps= 1e-8;
struct LINE{
    double hei, lef, rig;
    int side;
}line[maxn];
struct node{
    int lef, rig, mid, cnt;
    double once, twice;
}seg[4*maxn];
int n, cnt;
double pos[maxn];
bool cmp( LINE x, LINE y){
    return x.hei< y.hei;
}
void init(){
    scanf("%d", &n);
    int i, j, k;
    double x1, y1, x2, y2;
    for( i=0, cnt= 0; i<n; i++){
        scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
        pos[cnt]= x1;
        line[cnt].hei= y1;
        line[cnt].lef= x1;
        line[cnt].side= 1;
        line[cnt++].rig= x2;

        line[cnt].hei= y2;
        line[cnt].lef= x1;
        line[cnt].rig= x2;
        line[cnt].side= -1;
        pos[cnt++]= x2;
    }
    sort( pos, pos+ cnt);
    sort( line, line+ cnt, cmp);
    for( i=0, cnt= 0; i<2*n; i++){
        if( i== 0 || pos[i] != pos[i-1])
            pos[cnt++]= pos[i];
    }
}
void maketree(int num, int lef, int rig){
    seg[num].lef= lef;
    seg[num].rig= rig;
    seg[num].mid= (lef + rig) >> 1;
    seg[num].cnt= 0;
    seg[num].once= seg[num].twice= 0.0;
    if( lef != rig){
        maketree( LL(num), lef, seg[num].mid);
        maketree( RR(num), seg[num].mid+1, rig);
    }
}
int binary( double x){
    int l= 0, r= cnt-1, mid;
    while( l <= r){
        mid= (l+ r)>> 1;
        if( fabs(x- pos[mid]) <eps) break;
        else if( x- pos[mid] < 0) r= mid - 1;
        else l= mid + 1;
    }
    return mid;
}
void update( int num){
    if( seg[num].cnt > 0)
        seg[num].once= pos[seg[num].rig + 1]- pos[seg[num].lef];
    else if( seg[num].lef== seg[num].rig)
        seg[num].once= 0;
    else
        seg[num].once= seg[LL(num)].once + seg[RR(num)].once;

    if( seg[num].cnt > 1)
        seg[num].twice= pos[seg[num].rig + 1]- pos[seg[num].lef];
    else if( seg[num].lef == seg[num].rig)
        seg[num].twice= 0;
    else if( seg[num].cnt == 1)
        seg[num].twice= seg[RR(num)].once + seg[LL(num)].once;
    else
        seg[num].twice= seg[LL(num)].twice + seg[RR(num)].twice;

}
void insert( int num, int lef, int rig, int val){
    if( seg[num].lef== lef && seg[num].rig == rig){
        seg[num].cnt+= val;
        update( num);
        return ;
    }
    if( lef > seg[num].mid) insert( RR(num), lef, rig, val);
    else if( rig<= seg[num].mid) insert( LL(num),lef, rig, val);
    else {
        insert( LL(num), lef, seg[num].mid, val);
        insert( RR(num), seg[num].mid+1, rig, val);
    }
    update(num);
}
void handle(){
    int x1, x2, y1, y2;
    int i, j, k;
    double ans= 0;
    for( i=0; i<2*n-1; i++){
        x1= binary( line[i].lef);
        x2= binary( line[i].rig) - 1;
        insert( 1, x1, x2, line[i].side);
        ans+= seg[1].twice *( line[i+1].hei - line[i].hei);
    }
    printf("%.2f\n", ans);
}
int main(){
   // freopen("1.txt", "r", stdin);
    int i, j, k, T;
    scanf("%d", &T);
    while( T--){
        init();
        maketree(1, 0, cnt-1);
        handle();
    }
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值