HDU 1255(线段树 + 离散化 + 扫描线)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1255

思路: 与扫描线求面积并类似。在面积并的基础上 多增加一个 sum2[] 数组,存放覆盖两次及以上的投影。具体看代码

AC代码:

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

const int maxn = 2220;
struct xx{
    double l,r,h;
    int d;
    xx(){}
    xx(double l,double r,double h,int d):l(l),r(r),h(h),d(d){}
}line[maxn];
double sum[maxn << 2];
double sum2[maxn << 2];
double x[maxn];
int cnt[maxn << 2];

bool cmp(xx A, xx B){
    return A.h < B.h;
}

///两个pushup函数也可以写为一个
void pushup(int l,int r,int i){
    if(cnt[i]) sum[i] = x[r+1] - x[l];
    else if(l == r) sum[i] = 0;
    else sum[i] = sum[i<<1] + sum[i<<1|1];
}

void pushup2(int l,int r,int i){
    if(cnt[i] > 1)                              ///如果当前结点区间已经是第二次或以上被覆盖 直接算出其投影长度
        sum2[i] = x[r+1] - x[l];
    else if(cnt[i] == 1)                       ///如果 == 1 , 则等于子区间被覆盖过一次的线段长度之和
        sum2[i] = sum[i<<1] + sum[i<<1|1];
    else if(l == r)                            ///显然,叶子节点 == 0.
        sum2[i] = 0;
    else sum2[i] = sum2[i<<1] + sum2[i<<1|1];  ///若整体没被标记过,则等于子区间被覆盖过俩次的线段长度之和
}
/*
void build(int l,int r,int i){
    sum[i] = cnt[i] = sum2[i] = 0;
    if(l == r) return ;
    int mid = (l + r) >> 1;
    build(l,mid,i << 1);
    build(mid + 1,r,i << 1 | 1);
}
*/
void update(int l,int r,int ul,int ur,int key,int i){
    if(ul <= l && r <= ur){
        cnt[i] += key;
        pushup(l,r,i);
        pushup2(l,r,i);
        return ;
    }
    int mid = (l + r) >> 1;
    if(ul <= mid) update(l,mid,ul,ur,key,i << 1);
    if(ur > mid) update(mid + 1,r,ul,ur,key,i << 1 | 1);
    pushup(l,r,i);
    pushup2(l,r,i);
}

int main()
{
    int t; scanf("%d",&t);
    int n;
    while(t--){
        scanf("%d",&n);
        int pl = 1;
        double x1,x2,y1,y2;
        for(int i = 0;i < n;i ++){
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            line[pl] = xx(x1,x2,y1,1);
            x[pl ++] = x1;
            line[pl] = xx(x1,x2,y2,-1);
            x[pl ++] = x2;
        }
        sort(line + 1,line + pl,cmp);
        sort(x + 1,x + pl);
        int m = unique(x + 1,x + pl) - x - 1;

        memset(cnt,0,sizeof(cnt));
        memset(sum,0,sizeof(sum));
        memset(sum2,0,sizeof(sum2));

        double ans = 0;
        for(int i = 1;i < pl;i ++){
            int l = lower_bound(x + 1,x + m + 1,line[i].l) - x;
            int r = lower_bound(x + 1,x + m + 1,line[i].r) - x - 1;
            update(1,m,l,r,line[i].d,1);
            ans += sum2[1] * (line[i+1].h - line[i].h);
        }
        printf("%.2lf\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/no_o_ac/article/details/81228818
今日推荐