poj1151 线段树X扫描线X离散

一开始为了节省时间设了-1.

遇到0就不往下搜,结果没想清楚,各种bug.


基本思路就是离散化x的小数(详细点的说明在这里).

用平行x轴的扫描线扫描整个区域.

每次扫描把已经染色的长度算(endis[r]-endis[l])出来,乘以这次于上一次y的差就是本次的差.

还有就是区间的连续,也就是为什么是(endis[r]-endis[l]),这里用的是叶节点为[1,2][[2,3]...这种划分.就避免了需要判断是否区间连续.


/**********************
    hash x
    scan line on y
**********************/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <set>
#define lson num<<1
#define rson num<<1|1
#define gl l,(l+r)>>1,lson
#define gr (l+r)>>1,r,rson
using namespace std;

const int maxn = 100005;

struct ord  ///save order
{
    double y,x[2];
    int flag;
}o[210];

bool ord_cmp (ord a,ord b) {return a.y<b.y;}

int st[500<<3]; 


void push_down(int num) ///push_down without hesitates
{
    st[lson]+=st[num];
    st[rson]+=st[num];
    st[num]=0;
}

void push_up(int num)   ///push_up  without hesitates
{
    int v=min(st[lson],st[rson]);
    st[num]+=v;
    st[lson]-=v;
    st[rson]-=v;
}

void updata(int a,int b,int v,int l,int r,int num)
{
    if(a<=l&&r<=b)
    {
        st[num]+=v;
        push_up(num);
        return;
    }

    if(l+1==r)
        return;

    push_down(num);

    updata(a,b,v,gl);
    updata(a,b,v,gr);

    push_up(num);
}

map<double,int> dis;    ///discrete
map<int,double>endis;   ///continuous
set<double>buf;         ///buffer for dis

double calc(int l,int r,int num)
{
    if(st[num])
        return endis[r]-endis[l];
    if(l+1==r)
        return 0;

    push_down(num);

    return calc(gl)+calc(gr);
}
int main()
{
    #ifndef ONLINE_JUDGE
        freopen("poj1151.in","r",stdin);
    #endif // ONLINE_JUDGE
    int n,cas=1;
    while(~scanf("%d",&n)&&n)
    {
        buf.clear();
        dis.clear();
        endis.clear();

        for(int i=0;i<n;i++)
        {
            double a,b,c,d;
            scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
            buf.insert(a);
            buf.insert(c);
            o[i*2+1].x[0]=o[i*2].x[0]=min(a,c);
            o[i*2+1].x[1]=o[i*2].x[1]=max(a,c);
            o[i*2].y=min(b,d);
            o[i*2+1].y=max(b,d);
            o[i*2].flag=1;
            o[i*2+1].flag=-1;
        }
        sort(o,o+n*2,ord_cmp);

        int cnt=1;
        for(set<double>::iterator i=buf.begin(),end=buf.end();i!=end;i++,cnt++)
        {
            pair<double,int>tmp1(*i,cnt);
            pair<int,double>tmp2(cnt,*i);

            dis.insert(tmp1);
            endis.insert(tmp2);
        }

        n*=2;
        int m=buf.size();
        double ans=0,last=o[0].y;
        for(int i=0;i<n;i++)
        {
            int a=dis[o[i].x[0]],b=dis[o[i].x[1]];

            if(last!=o[i].y)
            {
                ans+=calc(1,m,1)*(o[i].y-o[i-1].y);
                last = o[i].y;
            }
            updata(a,b,o[i].flag,1,m,1);
        }
        printf("Test case #%d\nTotal explored area: %.2f\n\n",cas++,ans);
    }
    return 0;
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值