【题目】
原题地址
题目大意:
在一个白色平面内依次放入n种不同颜色的矩形(可以覆盖),全部放入后能看到多少种不同颜色的矩形(包括平面的白色)。
【解题思路】
这道题真是一道很不错的数据结构题,想了茫茫久……当然应该是因为我太弱了。
首先离散化什么的就不用多说了。
我们考虑能看见一个矩形的条件,如果我们按 x x 轴做扫描线,那么实际上就是要看这个矩形是否在某一个 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) n o w m x = m a x ( l s m x , r s m x , q m x ) , n o w m n = m a x ( m i n ( l s m n , r s m n ) , q m x )
显然当 mx<mn m x < m n 时,说明当前区间已经没有可以统计答案的颜色了,我们可以移动扫描线。
总的时间和空间复杂度都是 O(nlog2n) O ( n l o g 2 n ) 的。
【参考代码】
#include
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.opreturn 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"<if(!col[x].empty())
{
int t=col[x].top();
//cerr<<"unhappy"<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<" "<" "<if(L<=l && r<=R)
{
//cerr<<"happy"<if(v>0)
col[x].push(v);
else
if(v<0)
col[x].erase(-v);
//cerr<<"happy"<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(r1].x==p[l].x)
++r;
while(l<=r)
{
//cerr<" "<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;
}
【总结】
各种神神奇奇的数据结构套路快来虐我吧!