• [蓝桥杯][2017年第八届真题]油漆面积


    扫描线。

    我们取出(N)个矩形的左右边界。若一个矩形的两个对角顶点坐标为((x_1,y_1))((x_2,y_2)),则左边界记为四元组((x_1,y_1,y_2,1)),右边界记作四元组$(x_2,y_1,y_2,-1)。把这(2N)个四元组按照(x)递增排序。

    逐一扫描排序后的(2N)个四元组,设当前四元组为((x,y_1,y_2,mark))。我们把数组(tr)(tr[y_1],tr[y_1+1],cdots,tr[y_2-1])这些值都加上(mark),相当于覆盖了$[y_1,y_2]这个区间。

    值得说明的是,四元组中的(y_1,y_2)都是坐标,是一个“点”。我们需要维护的是扫描线上每一段被覆盖的次数及其西长度,对“点”的覆盖次数进行统计是没有意义的。因此,我们把(tr)数组中的每个值(tr[i])定义成扫描线上一个区间,即([i,i+1])的覆盖次数,四元组((x,y_1,y_2))(tr[y_1 sim y_2-1])产生影响。

    const int N=10010;
    struct Seg
    {
        int x,y1,y2;
        int mark;
        bool operator<(const Seg &W) const
        {
            return x < W.x;
        }
    }seg[N<<1];
    struct Node
    {
        int l,r;
        int cnt;
        int len;
    }tr[N<<2];
    int n;
    int cnt;
    
    void pushup(int u)
    {
        if(tr[u].cnt) tr[u].len=tr[u].r-tr[u].l+1;
        else
        {
            if(tr[u].l == tr[u].r) tr[u].len=0;//特判叶子结点,叶子结点不能借助左右儿子更新,否则会Segmentation Fault
            else tr[u].len=tr[lc].len+tr[rc].len;
        }
    }
    
    void build(int u,int l,int r)
    {
        tr[u]={l,r};
        if(l == r) return;
        int mid=l+r>>1;
        build(lc,l,mid);
        build(rc,mid+1,r);
    }
    
    void modify(int u,int l,int r,int mark)
    {
        if(tr[u].l >= l && tr[u].r <= r)
        {
            tr[u].cnt+=mark;
            pushup(u);
        }
        else
        {
            int mid=tr[u].l+tr[u].r>>1;
            if(l<=mid) modify(lc,l,r,mark);
            if(r>mid) modify(rc,l,r,mark);
            pushup(u);
        }
    }
    
    int main()
    {
        cin>>n;
    
        for(int i=0;i<n;i++)
        {
            int x1,y1,x2,y2;
            cin>>x1>>y1>>x2>>y2;
            seg[cnt++]={x1,y1,y2,1};
            seg[cnt++]={x2,y1,y2,-1};
        }
    
        sort(seg,seg+cnt);
    
        build(1,0,10000);
    
        int res=0;
        for(int i=0;i<cnt;i++)
        {
            if(i) res+=tr[1].len*(seg[i].x-seg[i-1].x);
            modify(1,seg[i].y1,seg[i].y2-1,seg[i].mark);
        }
        cout<<res<<endl;
        //system("pause");
        return 0;
    }
    
  • 相关阅读:
    总结对象和数组存储东东的缺点和优点
    this关键字
    修改对象属性的方法
    调用对象属性的两种方式
    数组可储存的东西
    对比字面量和结构函数创建对象的相同之处和不同之处
    构造函数创建对象
    字面量创建对象
    SQL语句
    使用SQL Server 2008的事务日志传送功能备份数据库(logshiping)
  • 原文地址:https://www.cnblogs.com/fxh0707/p/14588742.html
Copyright © 2020-2023  润新知