寒假Day48:HDU1542-Atlantis-矩形面积和-线段树+扫描线

题目链接:HDU - 1542 

样例:

Sample Input
2
10 10 20 20
15 15 25 25.5
0

Sample Output
Test case #1
Total explored area: 180.00 

题意:给出一个n,n≠0,给出n行数据,每一行给出一个矩形的左下角和右上角坐标(x1,y1,x2,y2)

每组数据输出n个矩形在坐标图上面的覆盖面积

思路:线段树扫描线模板题

注意:

line数组需要开两倍,因为每个矩形给出的是两个坐标。

线段树扫描线中的tree数组需要开8倍,一般线段树开4倍。

需要用到的数组和结构体:

const int N=110;

double y[N<<1];//记录y坐标

struct node
{
    int l,r,c;//线段树左右点、cover重叠覆盖情况
    double len,lf,rf;//实际情况
} tree[N<<3]; 

struct Line
{
    int f;//矩形:入边 左1 ,出边 右 -1
    double x,up,down;//线段的横坐标、上下纵坐标
} line[N<<1];

建树操作:

void build(int i,int L,int R)
{
    tree[i].l=L,tree[i].r=R;
    tree[i].c=tree[i].len=0;
    tree[i].lf=y[L],tree[i].rf=y[R];
    if(L+1==R)
        return ;
    int mid=(L+R)>>1;
    build(i<<1,L,mid);
    build(i<<1|1,mid,R);//不是mid+1,是[1,2][2,3],不是[1,2][3,4]
}

pushup操作:

void pushup(int i)//更新以下信息去维护整棵树
{
    if(tree[i].c)
    {
        tree[i].len=tree[i].rf-tree[i].lf;
        return;
    }
    //下面都是tree[i].c==0的,说明没有被覆盖
    if(tree[i].l+1==tree[i].r)//是叶子节点,
        tree[i].len=0;
    else//是一条整个区间没有被全部覆盖的线段
        tree[i].len=tree[i<<1].len+tree[i<<1|1].len;
}

update操作:

void update(int i,Line a)//加入一条新线段、更新线段树
{
    if(a.down==tree[i].lf&&a.up==tree[i].rf)
    {
        tree[i].c+=a.f;
        pushup(i);
        return;
    }
    if(a.up<=tree[i<<1].rf)
        update(i<<1,a);
    else if(a.down>=tree[i<<1|1].lf)
        update(i<<1|1,a);
    else
    {
        Line b=a,c=a;
        b.up=tree[i<<1].rf,c.down=tree[i<<1|1].lf;
        update(i<<1,b);
        update(i<<1|1,c);
    }
    pushup(i);
}

AC代码:

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;
#define inf 0x3f3f3f3f
typedef long long ll;
const int N=110;

double y[N<<1];//记录y坐标

struct node
{
    int l,r,c;//线段树左右点、cover重叠覆盖情况
    double len,lf,rf;//实际情况
} tree[N<<3];

struct Line
{
    int f;//矩形:入边 左1 ,出边 右 -1
    double x,up,down;//线段的横坐标、上下纵坐标
} line[N<<1];

bool cmp1(Line x,Line y)
{
    return x.x<y.x;
}

void build(int i,int L,int R)
{
    tree[i].l=L,tree[i].r=R;
    tree[i].c=tree[i].len=0;
    tree[i].lf=y[L],tree[i].rf=y[R];
    if(L+1==R)
        return ;
    int mid=(L+R)>>1;
    build(i<<1,L,mid);
    build(i<<1|1,mid,R);//不是mid+1,是[1,2][2,3],不是[1,2][3,4]
}

void pushup(int i)//更新以下信息去维护整棵树
{
    if(tree[i].c)
    {
        tree[i].len=tree[i].rf-tree[i].lf;
        return;
    }
    //下面都是tree[i].c==0的,说明没有被覆盖
    if(tree[i].l+1==tree[i].r)//是叶子节点,
        tree[i].len=0;
    else//是一条整个区间没有被全部覆盖的线段
        tree[i].len=tree[i<<1].len+tree[i<<1|1].len;
}

void update(int i,Line a)//加入一条新线段、更新线段树
{
    if(a.down==tree[i].lf&&a.up==tree[i].rf)
    {
        tree[i].c+=a.f;
        pushup(i);
        return;
    }
    if(a.up<=tree[i<<1].rf)
        update(i<<1,a);
    else if(a.down>=tree[i<<1|1].lf)
        update(i<<1|1,a);
    else
    {
        Line b=a,c=a;
        b.up=tree[i<<1].rf,c.down=tree[i<<1|1].lf;
        update(i<<1,b);
        update(i<<1|1,c);
    }
    pushup(i);
}

int main()
{
    int n,tt=1;
    while(~scanf("%d",&n)&&n)
    {
        int k=1;
        for(int i=1; i<=n; i++)
        {
            double x1,y1,x2,y2;
            scanf("%lf %lf %lf %lf",&x1,&y1,&x2,&y2);
            line[k].x=x1,line[k].down=y1,line[k].up=y2,line[k].f=1;
            y[k++]=y1;
            line[k].x=x2,line[k].down=y1,line[k].up=y2,line[k].f=-1;
            y[k++]=y2;
        }
        sort(line+1,line+k,cmp1);
        sort(y+1,y+k);
        build(1,1,k-1);
        update(1,line[1]);
        double ans=0;
        for(int i=2; i<k; i++)//扫描线段
        {
            ans+=tree[1].len*(line[i].x-line[i-1].x);//增加新的面积
            update(1,line[i]);
        }
        printf("Test case #%d\n",tt++);
        printf("Total explored area: %.2f\n\n",ans);//两个\n
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/OFSHK/p/12465693.html