矩形面积交-线段树

hdu - 1255

世事总是如此地无常,很多事情总在意料之外。

比如,这题。

不知道是如何错的,是因为二分写得不好?


做完矩形周长并之后,就把这个代码加了两个0,就过了。

又是maxn开小了。


下面是正确代码。

建议: 学矩形周长并、面积交,先学矩形面积并。

Pro: 0

Sol:

date:
*/
#include<iostream>
#include <cstdio>
#include<algorithm>
#include <cstring>
#define eps 1e-10
#define maxn    101000
#define lson l,m, rt << 1
#define rson m + 1,r, rt << 1 | 1
using namespace std;
struct Seg{
    double l,r,y;
    int sign;
    Seg(){}
    Seg(double ll, double rr, double yy, int ss):l(ll),r(rr),y(yy),sign(ss){}
    bool operator < (const Seg &cmp) const{
        if(y == cmp.y)  return sign > cmp.sign;
        return y < cmp.y;
    }
}seg[maxn << 1];
//sum存的是全部被覆盖的长度,rep存的是被重复覆盖的长度
double sum[maxn << 2],rep[maxn];
//c存的是该区间被覆盖几次
int c[maxn << 2];
//存的是原值,用于离散化
double X[maxn << 1];
void push_up(int rt,int l, int r){
    if(c[rt])   sum[rt] = X[r + 1] - X[l];
    else if(l == r) sum[rt] = 0.0;
    else    sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];

    if(c[rt] >= 2)  rep[rt] = X[r + 1] - X[l];
    else if(l == r) rep[rt] = 0.0;
//这里需要讨论一下
    else if(c[rt] == 1) rep[rt] = sum[rt << 1] + sum[rt << 1 | 1];
    else    rep[rt] = rep[rt << 1] + rep[rt << 1 | 1];
}
void update(int L, int R, int ss, int l , int r, int rt){
    if(L <= l && r <= R){
        c[rt] += ss;
        push_up(rt,l,r);    return;
    }
    int m = (l + r) >> 1;
    if(L <= m)  update(L,R,ss,lson);
    if(R > m)   update(L,R,ss,rson);
    push_up(rt,l,r);
}
//二分的时候对double注意
//int bin(int low, int high, double key){
//    int mid;
//    while(low < high){
//        mid = (low + high) >> 1;
//        if(X[mid] - key + eps < 0)    low = mid + 1;
//        else    high = mid;
//    }
//    return low;
//}
int bin(int low, int high, double key){
    int mid;
    while(low <= high){
        mid = (low + high) >> 1;
        if(X[mid] == key)    return mid;
        if (X[mid] < key) low = mid + 1;
        else    high = mid - 1;
    }
    return -1;
}
int n,xx,t,s,p;
double x1,x2,y1,y2,ret;
void init(){
    memset(sum,0,sizeof(sum));
    memset(rep,0,sizeof(rep));
    memset(c,0,sizeof(c));
    s=0;  xx= 0;  p = 1;    ret = 0.0;
    return;
}
int main(){
    scanf("%d",&t);
    while(t --){
        scanf("%d",&n) ;
        init();
        for(int i = 0; i < n; i ++){
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            seg[s ++] = Seg(x1,x2,y1,1);
            seg[s ++] = Seg(x1,x2,y2,-1);
            X[xx ++] = x1;
            X[xx ++] = x2;
        }
        sort(X,X+xx);
        for(int i = 1; i < xx; i ++){
            if(X[i - 1] != X[i])    X[p ++] = X[i];
        }

        sort(seg,seg+s);    p --;
        for(int i = 0; i < s - 1; i ++){
            int l = bin(0,p,seg[i].l);
            int r = bin(0,p,seg[i].r) - 1;
//            cout << l << "      " << r << endl;
            if(l <= r) update(l,r,seg[i].sign,0,p - 1,1);
//            cout << rep[1] << "###" << endl;
//            cout << sum[1] << "&&&" << endl;
            ret +=  rep[1] * (seg[i + 1].y - seg[i].y);
        }
        printf("%.2lf\n",ret);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值