HDU 1255——覆盖的面积(矩形面积交:线段树+扫描线)

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

题意: 

给出N(N<=1000)个矩形,求至少被两个矩形的所覆盖的面积和。

思路:

和上篇博客 链接 求多个矩形面积交的思路很相像,那个是维护当前有效宽求面积并,这里只需将cnt[i]>=2的看做有效宽(因为cnt记录的是扫描线的覆盖情况,当某个区间被下底边至少覆盖了两次,那么这条边以上的面积是由至少两个以上的矩形交和而成)所以唯一的区别在于更新len(区间有效长度)时看cnt的情况。

代码:

#include<bits/stdc++.h>
#define lson l,mid,o<<1
#define rson mid+1,r,o<<1|1
#define N 2005
using namespace std;

int cnt[N<<2];
double len[N<<2];

double X[N<<1];
struct edge
{
    double l,r,h;
    int f;
    edge() {}
    edge(double l,double r,double h,int f):l(l),r(r),h(h),f(f) {}
    bool operator < (const edge &b) const
    {
        return h<b.h;
    }
} e[N<<1];

void push_up(int o)
{
    if(cnt[o<<1]==-1 || cnt[o<<1|1]==-1)
        cnt[o]=-1;
    else if(cnt[o<<1]!=cnt[o<<1|1])
        cnt[o]=-1;
    else
        cnt[o]=cnt[o<<1];

    len[o]=len[o<<1]+len[o<<1|1];
}

void push_down(int o,int l,int r)
{
    if(cnt[o]!=-1)
    {
        int mid=l+r>>1;
        cnt[o<<1]=cnt[o<<1|1]=cnt[o];
        len[o<<1]=(cnt[o]>=2 ? X[mid+1]-X[l] :0);
        len[o<<1|1]=(cnt[o]>=2 ? X[r+1]-X[mid+1] :0);
    }
}

void build(int l,int r,int o)
{
    if(l==r)
    {
        cnt[o]=0;
        len[o]=0.0;
        return;
    }
    int mid=l+r>>1;
    build(lson);
    build(rson);
    push_up(o);
}

void update(int L,int R,int v,int l,int r,int o)
{
    if(L<=l&&r<=R)
    {
        if(cnt[o]!=-1)
        {
            cnt[o]+=v;
            len[o]=(cnt[o]>=2 ? X[r+1]-X[l]:0);
            return;
        }
    }
    push_down(o,l,r);
    int mid=l+r>>1;
    if(L<=mid)
        update(L,R,v,lson);
    if(R>mid)
        update(L,R,v,rson);
    push_up(o);
}


int main()
{
    int n,t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        double x1,y1,x2,y2;
        for(int i=1; i<=n; i++)
        {
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            X[i]=x1,X[i+n]=x2;
            e[i]=edge(x1,x2,y1,1);
            e[i+n]=edge(x1,x2,y2,-1);
        }
        sort(e+1,e+1+2*n);
        int m=unique(X+1,X+1+2*n)-X-1;
        sort(X+1,X+1+m);
        build(1,m-1,1);         //m个不同的点分成m-1个区间

        double ans=0.0;
        for(int i=1; i<=2*n-1; i++)
        {
            int l=lower_bound(X+1,X+1+m,e[i].l)-X;
            int r=lower_bound(X+1,X+1+m,e[i].r)-X-1;
            //printf("%d %d\n",l,r);
            update(l,r,e[i].f,1,m-1,1);
            //printf("%f  %f\n",len[1],e[i+1].h-e[i].h);
            ans+=len[1]*(e[i+1].h-e[i].h);
        }
        printf("%.2lf\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/QuincyTan/article/details/83754334
今日推荐