• 《算法竞赛进阶指南》0x43 扫描线 POJ1151Atlantis


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

    实际上不下放lazytag就是一个保持另一层记录的过程。简单的来说,就是当cnt为0的时候,t[rt<<1].len+t[rt<<1|1].len才是真实信息,当cnt不为0的时候,这段的段长才是真实信息,t[rt<<1].len+t[rt<<1|1].len是把这个矩形去掉之后该段的覆盖情况。

    题目描述和解释什么的,我就不说了,我是看了lyd的《算法竞赛进阶指南》之后思考了lyd的lazytag不需要下放的说法,其实这是一个很简单的问题,我们只设定lazytag,但是并不下放,因为左右线段是同样的几段构成的,如果执行了对[x,y]段+=k的操作之后一个段的cnt不为0,说明他至少被一个矩形所覆盖,这个覆盖,指的是那个矩形的右边界还没有达到。可以想象这样的矩形一定存在,否则这段的cnt将会变成0。
    下面,当一个段在执行操作之后cnt变成了0,说明所有覆盖这个区间段的矩形的右边界都已经完了,刚刚执行的一定是对这个区间段的cnt-1的行为,因为cnt只可能是从1变成0,故刚刚扫描的边一定会一个矩形的右边界,对于这一段而言,这个矩形的右边界截断之后,这个[x_i-1,x_i]段的扫描线被覆盖长度是多少呢?答案就是在不放这个矩形的情况下,最后一次操作中这一段的两个子区间被覆盖的长度之和,之所以没有下放这个标记,就是为了造成这样一种局面:在这个段下面的两个子段,其实是没有放这最后一个矩形的局面,正好就把它所掩盖的小段的段长和记录了。这就是lyd的方法的来源说明。
    我们试想,这一段的宽度很大,在截断之后,会露出更短的段长,没有下放标记,就使得这些更短的段长的和都在两个字段中被记录了。通过对两个字段的段长和进行求和,就得到了这段的当前段长。

    代码:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int maxn = 10010;
    struct node{
        int l,r,cnt;
        double len;//维护被覆盖的次数以及覆盖的长度 
    }t[maxn<<3];
    int n;
    int T=0;
    struct P {//记录一条边 
        double x,y1,y2;
        int k;//记录左边还是右边 
        bool operator < (const P& o)const {//按照x进行排序 
            return x<o.x;
        }
    }a[maxn<<1];
    double raw[maxn<<1]; 
    int num;
    int get(double x){
        return lower_bound(raw+1,raw+num+1,x)-raw;
    }
    void build(int rt,int l,int r){
        t[rt].l=l;
        t[rt].r=r;
        t[rt].cnt=0;
        t[rt].len=0;
        if(l==r)return ;
        int mid=l+r>>1;
        build(rt<<1,l,mid);
        build(rt<<1|1,mid+1,r);
    } 
    void update(int rt,int L,int R,int C){
        if(t[rt].l>=L && t[rt].r<=R){
            t[rt].cnt+=C;
            if(t[rt].cnt==0){//该段没有被完全覆盖 
                if(t[rt].l==t[rt].r)t[rt].len=0;//叶结点
                else t[rt].len=t[rt<<1].len+t[rt<<1|1].len; 
            }else{
                t[rt].len=raw[t[rt].r+1]-raw[t[rt].l];
            }
            return ;
        }
        int mid=(t[rt].l+t[rt].r)>>1;
        if(L<=mid)update(rt<<1,L,R,C);
        if(R>mid)update(rt<<1|1,L,R,C);
    //    不可能是叶子结点,所以只有两种更新方式 
        if(t[rt].cnt)t[rt].len=raw[t[rt].r+1]-raw[t[rt].l];
        else t[rt].len=t[rt<<1].len+t[rt<<1|1].len;
    }
    void solve(){
        cout<<"Test case #"<<++T<<endl;
        for(int i=1;i<=n;i++){
            double x1,x2,y1,y2;
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            raw[2*i-1]=y1;
            raw[2*i]=y2;
            a[2*i-1].x=x1,a[2*i-1].y1=y1,a[2*i-1].y2=y2,a[2*i-1].k=1;
            a[2*i].x=x2,a[2*i].y1=y1,a[2*i].y2=y2,a[2*i].k=-1;
        }
        sort(raw+1,raw+2*n+1);
        num=unique(raw+1,raw+2*n+1)-(raw+1);
        build(1,1,num-1);//最多有num-1段 
        sort(a+1,a+2*n+1);//从x最小的开始扫描 
        double ans=0;
        for(int i=1;i<2*n;i++){
            int l=get(a[i].y1),r=get(a[i].y2)-1;
            update(1,l,r,a[i].k);
            ans+=t[1].len*(a[i+1].x-a[i].x);
        }
        printf("Total explored area: %.2f
    
    ",ans); 
    }
    int main(){
        while(cin>>n && n)solve();
        return 0;
    } 
  • 相关阅读:
    模糊查询(排除%等通配符并支持不连续关键字查询)
    ideal中运行manven常用操作
    ideal项目启动及问题
    FastJSON 转换List<T> ,Map<T,T>泛型失败 处理方法
    MySQL的SELECT ...for update
    CouchDB客户端开发—Java版
    Spring Data JPA 实例查询
    第一章 计算机网络概述
    第二章 物理层(二)
    Java常考面试题(一)
  • 原文地址:https://www.cnblogs.com/randy-lo/p/13299611.html
Copyright © 2020-2023  润新知