POJ P1151 Atlantis

目录:


题目:

传送门


分析:

为题目给的矩形的坐标是浮点型的,所以毫无疑问要离散化,我们以 y y 轴坐标来建立线段树(当然也可以以x轴,这样的话扫描线是上下方向的了),然后 zb z b 表示扫描线的下一个位置。求面积的就是
ans+=(zb[i].xzb[i1].x)t[1].cnt a n s + = ( z b [ i ] . x − z b [ i − 1 ] . x ) ∗ t [ 1 ] . c n t 。其实说白了扫描线就是一个区间操作的线段树:不过节点存的是 c c (这个整个的区间被覆盖的次数,如果为0,则这个整区间未被完全覆盖), cnt c n t 是整个区间所覆盖的长度。每次只需要更新这两个值就好了,设矩形的左边的权值是 1 1 ,右边的权值是1,每一条边覆盖是,总是带着权值覆盖的。


代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>  
#include<cstdlib>
#include<algorithm>
#include<set>
#include<queue>
#include<vector>
#include<map>
#include<list>
#include<ctime>
#include<iomanip>
#include<string>
#include<bitset>
#define LL long long
#define h happy
using namespace std;
inline LL read() {
    LL d=0,f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
    return d*f;
}
struct node{
    double x,y1,y2;
    int f;
}zb[205];
bool cmp(node x,node y)
{
    return x.x<y.x;
}
struct segment_tree{
    int l,r,c;
    double lc,rc,cnt;
}t[805];
double y[205];
void build(int p,int l,int r)
{
    t[p].l=l;t[p].r=r;
    t[p].cnt=t[p].c=0;
    t[p].lc=y[l];t[p].rc=y[r];
    if(l+1==r) return;
    int mid=(l+r)>>1;
    build(p*2,l,mid);
    build(p*2+1,mid,r);
    return;
}
void pushup(int p)
{
    if(t[p].c)
    {
        t[p].cnt=t[p].rc-t[p].lc;
        return;
    }
    if(t[p].l+1==t[p].r) t[p].cnt=0;
    else t[p].cnt=t[p*2].cnt+t[p*2+1].cnt;
    return;
}
void change(int p,node e)
{
    if(t[p].lc==e.y1&&t[p].rc==e.y2)
    {
        t[p].c+=e.f;
        pushup(p);
        return;
    }
    int mid=(t[p].l+t[p].r)>>1;
    if(e.y2<=y[mid]) change(p*2,e);
    else if(e.y1>=y[mid]) change(p*2+1,e);
    else
    {
        node line=e;
        line.y2=y[mid];
        change(p*2,line);
        line=e;
        line.y1=y[mid];
        change(p*2+1,line);
    }
    pushup(p);
    return;
}
int main()
{
    int n=read(),k=0;
    while(n)
    {
        int cnt=0;
        printf("Test case #%d\n",++k);
        for(int i=1;i<=n;i++)
        {
            double a,b,c,d;
            scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
            zb[++cnt].x=a;zb[cnt].y1=b;zb[cnt].y2=d;zb[cnt].f=1;
            y[cnt]=b;
            zb[++cnt].x=c;zb[cnt].y1=b;zb[cnt].y2=d;zb[cnt].f=-1;
            y[cnt]=d;
        }
        sort(zb+1,zb+1+cnt,cmp);
        sort(y+1,y+1+cnt);
        build(1,1,cnt);
        double ans=0;
        change(1,zb[1]);
        for(int i=2;i<=cnt;i++)
        {
            ans+=t[1].cnt*(zb[i].x-zb[i-1].x);
            change(1,zb[i]);
        }
        printf("Total explored area: %.2lf\n\n",ans);
        n=read();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值