POJ 1151 扫描线

链接:http://poj.org/problem?id=1151

题意:求所有矩形覆盖的面积

思路:扫描线。扫描线倒是很快就看懂了,不过在线段树处理的时候弄懵了。

这道题求得比较特殊,就是求sum【1】,其他的值没有用,所以更新方式也比较奇怪= =


虽然是区间更新,lazy值并没有向下传递,而是只更新最上面(线段树)覆盖的区间,求值的时候根据当前区间的标记值,如果区间被覆盖了就是左右端点距离,如果是叶子节点且未覆盖就是0,否则就是左右子节点的和。

考虑下不向下更新是否正确:

1.父节点被覆盖:子节点的值对父节点没有影响,因为由父节点向上更新的时候直接由左右端点计算。

2.父节点未被覆盖:未被覆盖就不用向下更新,父节点的值由左右子节点求出


这道题是用端点表示的,于是用左端点表示一个区间,就和普通的线段树类似了。

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <stack>
using namespace std;
#define mem(a,b) memset((a),(b),sizeof((a)))
#define For(i,a,b) for(int (i)=(a);(i) < (b);(i)++)
#define Ror(i,a,b) for(int (i)=(a);(i) > (b);(i)--)
#define mp make_pair
#define pb push_back
#define inf 0x3f3f3f3f
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1

void RI (int& x){
    x = 0;
    char c = getchar ();
    while (c == ' '||c == '\n')    c = getchar ();
    bool flag = 1;
    if (c == '-'){
        flag = 0;
        c = getchar ();
    }
    while (c >= '0' && c <= '9'){
        x = x * 10 + c - '0';
        c = getchar ();
    }
    if (!flag)    x = -x;
}
void RII (int& x, int& y){RI (x), RI (y);}
void RIII (int& x, int& y, int& z){RI (x), RI (y), RI (z);}


const int maxn = 100100;
int ff[maxn<<2];
double sum[maxn<<2];
double xx[210];
void pushup(int rt,int l,int r){
    if(ff[rt])sum[rt] = xx[r] - xx[l-1];
    else if(l == r)sum[rt] = 0;
    else sum[rt] = sum[rt<<1] + sum[rt<<1|1];
    
}
void update(int L,int R,int c,int l,int r,int rt){
    //[L,R]更新区间,[l,r]当前区间
    if(L <= l&&r <= R){
        ff[rt] += c;
        pushup(rt,l,r);
        return ;
    }
    int m = (l + r) >> 1;
    if(R <= m)update(L,R,c,lson);
    else if(L > m)update(L,R,c,rson);
    else {
        update(L,m,c,lson);
        update(m+1,R,c,rson);
    }
    pushup(rt,l,r);
}
struct Seg{
    double l,r;
    double h;
    int ff;
}seg[210];
bool cmp(Seg a,Seg b){
    return a.h < b.h;
}
int main(){
    //freopen("test.txt","r",stdin);
    int n;
    int cas = 1;
    while(1){
        RI(n);
        if(n == 0)break;
        For(i,0,n){
            double xa,ya,xb,yb;
            cin>>xa>>ya>>xb>>yb;
            seg[2*i] = (Seg){xa,xb,ya,1};
            seg[2*i+1] = (Seg){xa,xb,yb,-1};
            xx[2*i] = xa;
            xx[2*i+1] = xb;
        }
        sort(seg,seg+n*2,cmp);
        
        sort(xx,xx+n*2);
        int siz = unique(xx,xx+n*2) - xx;

        //For(i,0,siz+1)cout<<xx[i]<<' ';cout<<endl;

        mem(sum,0);
        mem(ff,0);
        double ans = 0;
        For(i,0,2*n-1){
            int l = lower_bound(xx,xx+siz,seg[i].l)-xx+1;
            int r = lower_bound(xx,xx+siz,seg[i].r)-xx;
            
            update(l,r,seg[i].ff,1,siz-1,1);//cout<<sum[1]<<' '<<l<<' '<<r<<endl;
            ans += sum[1]*(seg[i+1].h - seg[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、付费专栏及课程。

余额充值