zoukankan      html  css  js  c++  java
  • 扫描线

    题目链接

    考虑将每个矩形看做两次操作,分别是在$Y$轴上叠加线段和去除线段。按$X$坐标排序后依次访问扫过。

    注意:本题中,坐标表示的是直角坐标系的整点坐标,也即我们计算的是连续的面积,不过这里矩形都是水平的。

    那么离散化一波,每个离散点表示到它的后继之间的线段。

    考虑使用线段树,维护“覆盖计数”和“有效线段长”。

    本题的线段树虽然是区间修改区间查询,但注意到本题的区间查询实际上都只在询问全区间,也即,如果写传统的区间询问函数,访问完根节点,都不会往下递归。

    那么不需要做“覆盖计数”的懒标记了,只要每次精准定位$O(log n)$个区间修改,注意每次回溯都维护一下“有效线段长”就行了。

    具体方案是,如果一个区间被全覆盖了,那么它的“有效线段长”就是区间原长度。否则就是两个子区间的答案相加。

    这里有一个细节,当你访问未被覆盖或者正好被去除覆盖的叶子结点时,你会尝试访问它的子区间。这显然是错误的,要么特判该情况时“有效线段长”为$0$,要么将数组大小翻倍来无视该情况。

    代码(100分):

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #include<map>
    #include<set>
    #define IL inline
    #define RG register
    #define _1 first
    #define _2 second
    using namespace std;
    typedef long long LL;
    const int N=2e5;
    
        int n,m,a[N+3];
        
    struct Lne{
        int d,x,y,t;
        Lne(int d=0,int x=0,int y=0,int t=0)
            :d(d),x(x),y(y),t(t){}
    }p[N+3];
    
    IL bool operator<(Lne x,Lne y){
        return x.d<y.d;
    }
    
    IL int sol(int x){
        int l=1,r=m,mid,ans;
        while(l<=r){
            mid=(l+r)>>1;
            if(x<=a[mid]){
                r=mid-1;    ans=mid;
            }
            else 
                l=mid+1;
            
        }
        return ans;
        
    }
    
    IL void discrete(){
        n<<=1;
        sort(a+1,a+n+1);
        m=1;
        for(int i=2;i<=n;i++)
        if(a[i]!=a[i-1])
            a[++m]=a[i];
        
        for(int i=1;i<=n;i+=2){
            p[i].x=p[i+1].x=sol(p[i].x);
            p[i].y=p[i+1].y=sol(p[i].y);
            
        }
        
    }
    
        int c[N*4+3],s[N*4+3];
        
    IL int ls(int i){return i<<1;}
    IL int rs(int i){return i<<1|1;}
        
    IL void merge(int i,int l,int r){
        if(c[i])
            s[i]=a[r+1]-a[l];
        else 
            if(l==r)
                s[i]=0;
            else 
                s[i]=s[ls(i)]+s[rs(i)];
            
    }
    
    void mdf(int i,int l,int r,int ql,int qr,int x){
        if(ql<=l&&r<=qr){
            c[i]+=x;
            merge(i,l,r);
            return ;
            
        }
        
        int mid=(l+r)>>1;
        if(ql<=mid)
            mdf(ls(i),l,mid,ql,qr,x);
        if(qr>mid)
            mdf(rs(i),mid+1,r,ql,qr,x);
        merge(i,l,r);
        
    }
    
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            int x1,y1,x2,y2;
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            a[i*2-1]=y1;
            a[i<<1]=y2;
            p[i*2-1]=Lne(x1,y1,y2,1);
            p[i<<1]=Lne(x2,y1,y2,-1);
            
        }
        
        discrete();
        sort(p+1,p+n+1);
        LL ans=0;
        for(int i=1;i<n;i++){
            mdf(1,1,m,p[i].x,p[i].y-1,p[i].t);
            ans+=1LL*s[1]*(p[i+1].d-p[i].d);
            
        }
        
        printf("%lld",ans);
    
        return 0;
    
    }
    View Code
  • 相关阅读:
    【ASP.NET】服务器控件大演练与实例分析
    【利用存储过程和三层架构完成新闻发布】
    【软件工程】web规格开发全过程
    【数据库】如何解决数据库附加失败问题
    【框架设计】异常
    【数据库】SqlCommand的几个易忽视的执行操作
    【ASP.NET】asp.net 页面调用服务端对象值
    【c#迭代器】
    【框架设计】CLR寄宿和应用程序域
    【ASP.NET】演绎GridView基本操作事件
  • 原文地址:https://www.cnblogs.com/Hansue/p/12976898.html
Copyright © 2011-2022 走看看