【扫描线+线段树+堆】Codeforces 983D Arkady and Rectangles

【题目】
原题地址
题目大意:
在一个白色平面内依次放入n种不同颜色的矩形(可以覆盖),全部放入后能看到多少种不同颜色的矩形(包括平面的白色)。

【解题思路】
这道题真是一道很不错的数据结构题,想了茫茫久……当然应该是因为我太弱了。
首先离散化什么的就不用多说了。

我们考虑能看见一个矩形的条件,如果我们按 x x 轴做扫描线,那么实际上就是要看这个矩形是否在某一个x上有出现过。
怎么样才能让它出现呢?显然就是比它后的矩形在这个 x x 上都没有将它覆盖掉。
那么问题就转化为维护一个区间最大值的数据结构,我们上线段树就可以了。

考虑对于当前的x,可能同时可以看到多个颜色,因此在得到一个最大值以后,我们需要从下面将最大值更新,得到另一个颜色。
我们设计这样的标记: mx m x mn m n mx m x 表示当前区间能看到的编号最大且未统计答案的颜色, mn m n 表示当前区间覆盖的最小的颜色。
为了更新,我们还要维护一个存储当前区间所有为统计答案颜色的数据结构,且支持删除一个给定值、取出一个最大值,这个用堆就可以了,记为 q q
那么nowmx=max(lsmx,rsmx,qmx),nowmn=max(min(lsmn,rsmn),qmx)
显然当 mx<mn m x < m n 时,说明当前区间已经没有可以统计答案的颜色了,我们可以移动扫描线。

总的时间和空间复杂度都是 O(nlog2n) O ( n l o g 2 n ) 的。

【参考代码】

#include<bits/stdc++.h>
using namespace std;

const int N=1e5+10;
int n,tot;
int w1[N<<1],w2[N<<1];
bool vis[N];

struct Tdata
{
    int x,op,id;
};
Tdata p[N<<1];

bool cmp(Tdata A,Tdata B)
{
    if(A.x==B.x)
        return A.op<B.op;
    return A.x>B.x;
}

struct Tnode
{
    int xl,yl,xr,yr;
};
Tnode a[N];

struct Tqueue
{
    priority_queue<int>q,p;
    void dele(){
        while(!p.empty() && q.top()==p.top())
            q.pop(),p.pop();
    }
    int top(){
        dele();return q.top();
    }
    bool empty(){
        dele();return q.empty();
    }
    void push(int x){
        q.push(x);
    }
    void erase(int x){
        p.push(x);
    }
};

struct Seqment
{
    int mx[N<<3],mn[N<<3];
    Tqueue col[N<<3];

    void update(int x,int l,int r)
    {
        if(l^r)
        {
            mn[x]=min(mn[x<<1],mn[x<<1|1]);
            mx[x]=max(mx[x<<1],mx[x<<1|1]);
        }
        else
            mn[x]=mx[x]=0;
        //cerr<<"unhappy"<<endl;
        if(!col[x].empty())
        {
            int t=col[x].top();
        //cerr<<"unhappy"<<endl;
            if(vis[t])
                mn[x]=max(mn[x],t);
            else
                mx[x]=max(mx[x],t);
            if(mn[x]>mx[x])
                mx[x]=0;
        }
    }

    void ins(int x,int l,int r,int L,int R,int v)
    {
        //cerr<<l<<" "<<r<<" "<<v<<endl;
        if(L<=l && r<=R)
        {
            //cerr<<"happy"<<endl;
            if(v>0)
                col[x].push(v);
            else
            if(v<0)
                col[x].erase(-v);
            //cerr<<"happy"<<endl;
            update(x,l,r);
            return;
        }
        int mid=(l+r)>>1;
        if(L<=mid)
            ins(x<<1,l,mid,L,R,v);
        if(R>mid)
            ins(x<<1|1,mid+1,r,L,R,v);
        update(x,l,r);
    }
}tr;

int read()
{
    int ret=0,f=1;char c=getchar();
    while(!isdigit(c)){if(c=='-')f=0;c=getchar();}
    while(isdigit(c)){ret=ret*10+(c^48);c=getchar();}
    return f?ret:-ret;
}

int main()
{
#ifndef ONLINE_JUDGE
    freopen("CF983D.in","r",stdin);
    freopen("CF983D.out","w",stdout);
#endif
    n=read();
    for(int i=1;i<=n;++i)
    {
        a[i].xl=read();a[i].yl=read();a[i].xr=read();a[i].yr=read();
        w1[i]=a[i].xl;w1[i+n]=a[i].xr;
        w2[i]=a[i].yl;w2[i+n]=a[i].yr;
    }
    sort(w1+1,w1+n*2+1);sort(w2+1,w2+n*2+1);
    for(int i=1;i<=n;++i)
    {
        a[i].xl=lower_bound(w1+1,w1+n*2+1,a[i].xl)-w1;
        a[i].xr=lower_bound(w1+1,w1+n*2+1,a[i].xr)-w1;  
        a[i].yl=lower_bound(w2+1,w2+n*2+1,a[i].yl)-w2;
        a[i].yr=lower_bound(w2+1,w2+n*2+1,a[i].yr)-w2-1;
        p[++tot].x=a[i].xr;p[tot].op=0;p[tot].id=i;
        p[++tot].x=a[i].xl;p[tot].op=1;p[tot].id=i;
        //printf("%d %d %d %d\n",a[i].xl,a[i].yl,a[i].xr,a[i].yr);
    }
    sort(p+1,p+tot+1,cmp);

    int l=1,ans=0;
    while(l<=tot)
    {
        int r=l;
        while(r<tot && p[r+1].x==p[l].x)
            ++r;
        while(l<=r)
        {
            //cerr<<a[p[l].id].yl<<" "<<a[p[l].id].yr<<endl;
            if(!p[l].op)
                tr.ins(1,1,n<<1,a[p[l].id].yl,a[p[l].id].yr,p[l].id);
            else
                tr.ins(1,1,n<<1,a[p[l].id].yl,a[p[l].id].yr,-p[l].id);
            ++l;
        }
        while(tr.mx[1])
        {
            ++ans;
            int x=tr.mx[1];vis[x]=1;
            tr.ins(1,1,n<<1,a[x].yl,a[x].yr,0);
        }
    }
    printf("%d\n",ans+1);

    return 0;
}

【总结】
各种神神奇奇的数据结构套路快来虐我吧!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值