Codeforces483Div1 983D Arkady and Rectangles

18 篇文章 0 订阅
9 篇文章 0 订阅

题意:

在一个平面上,依次放入N个颜色不同的矩形(可能会覆盖),现在求最终状态下能看到多少种不同温度颜色。注:空白部分也视为一种颜色。
N100000 N ≤ 100000


分析:

这是一道比较有趣的数据结构题:
利用扫描线算法,首先将所有坐标离散化,然后按照正方向枚举x坐标,每次求出当前这个横坐标能看见的矩形,于是将每个矩形视作两条线段:
矩形的左侧视为加入当前矩形,右侧+1的位置视为删去当前矩形。
用线段树+set维护。
对于每个线段树上的节点,存储两个值与一个set,分别设为maxv,minv,S
maxv表示:当前区间内能够看见的,编号最大的未被标记的颜色。
minv表示:当前区间内被覆盖的最小的颜色。(用于更新maxv)
S存储覆盖了当前区间的所有颜色。

对于每次更新,首先求出左右儿子节点的maxv,minv,令当前节点的 maxv=max{maxvin left son,maxvin right son,maxvalin S and didt used} m a x v = m a x { m a x v i n   l e f t   s o n , m a x v i n   r i g h t   s o n , m a x v a l i n   S   a n d   d i d ′ t   u s e d }
minv=max{min{minvin left son,minvin right son},maxvalin S and didt used} m i n v = m a x { m i n { m i n v i n   l e f t   s o n , m i n v i n   r i g h t   s o n } , m a x v a l i n   S   a n d   d i d ′ t   u s e d } ,理解起来很容易,里层的min就是左右区间内的被覆盖颜色的最小值,而外层的max是因为:当前区间内都被这个值覆盖,所以取max。
然后,若 maxv<minv m a x v < m i n v ,说明当前maxv这个颜色一定被其他已更新颜色覆盖掉了,因为它连当前区间内最小的值都不够。所以将 maxv m a x v 修正为-1,即记为当前区间不含可以被更新的颜色。

每更新一次,继续判断根节点的maxv是否为-1,若不是则继续标记,若是则停止。

实现上有些细节要考虑:首先离散化后,必须区分“离散化后相邻”和“离散化前相邻”的情况(实现时就会发现了)。
并且,由于题目给出的是端点坐标,因此我们的矩形范围要作出相应改动,比如,两个点(0,1)与(0,2)之间,如果直接将这个作为矩形的边界位置(即将左端点设为1,右端点设为2),那么矩形就会有2的单位长度,但其实这个矩形只有1单位长度。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<set>
#define SF scanf
#define PF printf
#define MAXN 100010
using namespace std;
struct node{
    set<int> s;
    int mi,ma;  
    node *pl,*pr;
}tree[MAXN*12],*root=tree,*ncnt=tree;
bool used[MAXN];
struct block{
    int l,r,id,flag,x;
    block() {}
    block(int l1,int r1,int id1,int flag1,int x1):l(l1),r(r1),id(id1),flag(flag1),x(x1) {}
    bool operator < (const block&a) const{
        if(x==a.x)
            return l<a.l;
        return x<a.x;
    }
}blo[MAXN*2];
void build(node *x,int l,int r){
    x->mi=-1,x->ma=-1;
    if(l==r)    
        return ;
    int mid=(l+r)>>1;
    x->pl=++ncnt;
    build(x->pl,l,mid);
    x->pr=++ncnt;
    build(x->pr,mid+1,r);
}
void pushup(node *x){
    if(x->pl==NULL&&x->pr==NULL){
        if(x->s.empty()){
            x->ma=x->mi=-1;
            return; 
        }
        x->ma=*x->s.rbegin();
        x->mi=x->ma;
        if(used[x->ma]==1)
            x->ma=-1;
    }
    else{
        int &mi=x->mi,&ma=x->ma;
        mi=min(x->pl->mi,x->pr->mi),x->ma=max(x->pl->ma,x->pr->ma);
        if(x->s.empty())
            return ;
        int xs=*x->s.rbegin();
        mi=max(mi,xs);
        if(ma<xs){
            if(used[xs]==1)
                ma=-1;
            else{
                if(xs<mi)
                    ma=-1;
                else
                    ma=xs;
            }
        }
    }
}
void add(node *x,int l,int r,int l1,int r1,int val,int idx){
    if(l>=l1&&r<=r1){
        if(val==-1)
            x->s.erase(idx);
        else
            x->s.insert(idx);
        pushup(x);
        return ;
    }
    int mid=(l+r)>>1;
    if(mid>=l1)
        add(x->pl,l,mid,l1,r1,val,idx);
    if(mid<r1)
        add(x->pr,mid+1,r,l1,r1,val,idx);
    pushup(x);
}
void Update(node *x,int l,int r,int l1,int r1,int idx){
    if(l>=l1&&r<=r1){
        pushup(x);  
        return ;
    }
    int mid=(l+r)>>1;
    if(mid>=l1)
        Update(x->pl,l,mid,l1,r1,idx);
    if(mid<r1)
        Update(x->pr,mid+1,r,l1,r1,idx);
    pushup(x);
}
int n,sumx,sumy;
int apx[MAXN*6],apy[MAXN*6];
int ls[MAXN],rs[MAXN];
void pushx(int x){
    apx[++sumx]=x;
    apx[++sumx]=x-1;
    apx[++sumx]=x+1;
}
void pushy(int y){
    apy[++sumy]=y;
    apy[++sumy]=y-1;
    apy[++sumy]=y+1;    
}
int main(){
    SF("%d",&n);    
    int sx,sy,ex,ey,cnt=0;
    for(int i=1;i<=n;i++){
        SF("%d%d%d%d",&sx,&sy,&ex,&ey);
        ex--,ey--;
        blo[++cnt]=block(sy,ey,i,1,sx);
        blo[++cnt]=block(sy,ey,i,-1,ex+1);
        pushx(sx);
        pushx(ex+1);
        pushy(sy);
        pushy(ey);
    }
    sort(apx+1,apx+1+sumx);
    sort(apy+1,apy+1+sumy);
    sumx=unique(apx+1,apx+1+sumx)-(apx+1);
    sumy=unique(apy+1,apy+1+sumy)-(apy+1);
    for(int i=1;i<=cnt;i++){
        blo[i].l=lower_bound(apy+1,apy+1+sumy,blo[i].l)-apy;
        blo[i].r=lower_bound(apy+1,apy+1+sumy,blo[i].r)-apy;
        blo[i].x=lower_bound(apx+1,apx+1+sumx,blo[i].x)-apx;
    }
    for(int i=1;i<=cnt;i++){
        ls[blo[i].id]=blo[i].l;
        rs[blo[i].id]=blo[i].r;
    }
    sort(blo+1,blo+1+cnt);
    int las=1;
    build(root,1,sumy);
    /*for(int i=1;i<=cnt;i++)
        PF("{%d %d %d %d %d}\n",blo[i].l,blo[i].r,blo[i].x,blo[i].id,blo[i].flag);*/
    for(int i=1;i<=sumx;i++){
        while(las<=cnt&&blo[las].x==i){
            //PF("{%d %d %d %d}\n",blo[las].l,blo[las].r,blo[las].x,blo[las].id);
            add(root,1,sumy,blo[las].l,blo[las].r,blo[las].flag,blo[las].id);
            las++;
        }
        while(root->ma!=-1){
            int x=root->ma;
            used[x]=1;
            Update(root,1,sumy,ls[x],rs[x],x);
        }
    }
    int ans=1;
    for(int i=1;i<=n;i++)
        if(used[i]==1)
            ans++;
    PF("%d",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值