扫描线

首先推荐一篇大佬的博客:https://blog.csdn.net/xianpingping/article/details/83032798

题目:http://poj.org/problem?id=1151

扫描线裸题,主要是为了贴个板子

Ac code:

#include<stack>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<map>
#include<cstring>
using namespace std;
const int maxn=220;
struct Node{
    double l,r,h;
    int f;
    Node() {}
    Node(double a,double b,double c,int d):l(a),r(b),h(c),f(d) {}
    bool operator < (const Node& cmp) const
    {
        return h<cmp.h;
    }
}node[maxn];
struct node
{
    int cnt;
    double len;
} tree[maxn<<2];
double X[maxn<<1];
void pushdown(int l,int r,int rt)
{
    if(tree[rt].cnt)//当前的边被标记,就把当前的长度加上
        tree[rt].len=X[r+1]-X[l];///还原r
    else if(l==r)//当为一个点的时候长度为0
        tree[rt].len=0;
    else//其他情况把左右两个区间的值加上
        tree[rt].len=tree[rt<<1].len+tree[rt<<1|1].len;
}
void update(int L,int R,int l,int r,int rt,int val)
{
    if(L<=l&&r<=R)
    {
        tree[rt].cnt+=val;//加上标记的值
        pushdown(l,r,rt);//像下更新节点
        return;
    }
    int m=(l+r)>>1;
    if(L<=m) update(L,R,l,m,rt<<1,val);
    if(R>m) update(L,R,m+1,r,rt<<1|1,val);
    pushdown(l,r,rt);
}
int main()
{
    int n,cas=0;
    double x1,x2,y1,y2;
    while(scanf("%d",&n)!=EOF&&n)
    {
        memset(tree,0,sizeof tree);
        int num=0;
        for(int i=1; i<=n; i++)
        {
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            X[num]=x1;
            node[num++]=Node(x1,x2,y1,1);
            X[num]=x2;
            node[num++]=Node(x1,x2,y2,-1);
        }
        sort(node,node+num);
        sort(X,X+num);
        int m=unique(X,X+num)-X;
        double ans=0;
        for(int i=0;i<num;i++)
        {
            int l=lower_bound(X,X+m,node[i].l)-X;
            int r=lower_bound(X,X+m,node[i].r)-X-1;///-1是为了计算[mid,mid+1]的长度,按照普通线段树求法,[mid,mid+1]的长度会丢失
            update(l,r,0,m,1,node[i].f);
            ans+=tree[1].len*(node[i+1].h-node[i].h);
        }
        printf("Test case #%d\nTotal explored area: %.2f\n\n",++cas,ans);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值