题解 P4793 【[AHOI2008]矩形藏宝地】
yuzhechuan · · 题解
放一篇(可能)比较正常的cdq题解
题解:
题意显然是一个四维偏序,然而三只log的复杂度也显然是不优秀的
注意到题目只是让我们判定某个矩形能否被其他某一个矩形包括,而不是有几对关系,因此本题可以通过某些方法简化掉一层限制
考虑若矩形
假设我们此时已经用排序+分治干掉前两维了,
由于这是连贯且起始点是定值的区间,我们对他们记一个前缀min,看看对于某个点的左半边,有没有还比他低的点,这些点就是在它的左下角的了,在满足包住右上角的同时也能包住左下角,于是就可以判定矩形
前缀min是树状数组的一个经典应用,可以log解决
最后统计一下有几个矩形能被包住就是答案
另外还有一个小细节,为了优化大坐标带来的复杂度冗余,我们可以先对横纵坐标离散化一下
代码:
#include <bits/stdc++.h>
using namespace std;
template<class t> inline t read(t &x){
char c=getchar();bool f=0;x=0;
while(!isdigit(c)) f|=c=='-',c=getchar();
while(isdigit(c)) x=(x<<1)+(x<<3)+(c^48),c=getchar();
if(f) x=-x;return x;
}
template<class t> inline void write(t x){
if(x<0) putchar('-'),write(-x);
else{if(x>9) write(x/10);putchar('0'+x%10);}
}
#define dc divide_and_conquer
#define xn XN
#define yn YN
const int N=2e5+5;
int ans,xn,yn,numx[N<<1],numy[N<<1],tr[N<<1],n;
struct dc{
int x,y,xx,yy,ans;
inline bool operator < (const dc &nt) const{ //先按右上角的x排
return xx>nt.xx;
}
}a[N],b[N];
#define lowbit(x) (x&(-x))
void clear(int x){ //重新赋回无穷大
while(x<=xn){
tr[x]=0x3f3f3f3f;
x+=lowbit(x);
}
}
void up(int x,int v){ //修改
while(x<=xn){
tr[x]=min(tr[x],v);
x+=lowbit(x);
}
}
int que(int x){ //查询
int res=0x3f3f3f3f;
while(x){
res=min(res,tr[x]);
x-=lowbit(x);
}
return res;
}
void cdq(int l,int r){
if(l==r) return ;
int mid=l+r>>1;
cdq(l,mid);cdq(mid+1,r);
int p=l,q=mid+1,i=l-1;
while(p<=mid&&q<=r){
if(a[p].yy>a[q].yy){ //满足右上角能包住
up(a[p].x,a[p].y); //维护下前缀最小
b[++i]=a[p++];
}
else{
if(que(a[q].x)<a[q].y) a[q].ans=1; //若它的前面还有比他低的,就是被包住了
b[++i]=a[q++];
}
}
while(q<=r){
if(que(a[q].x)<a[q].y) a[q].ans=1;
b[++i]=a[q++];
}
for(int i=l;i<p;i++) clear(a[i].x); //复原树状数组
while(p<=mid) b[++i]=a[p++];
for(int i=l;i<=r;i++) a[i]=b[i];
}
signed main(){
read(n);
for(int i=1;i<=n;i++){
read(a[i].x);numx[++xn]=a[i].x;
read(a[i].y);numy[++yn]=a[i].y;
read(a[i].xx);numx[++xn]=a[i].xx;
read(a[i].yy);numy[++yn]=a[i].yy;
}
memset(tr,0x3f,sizeof tr); //初始赋无穷大
sort(numx+1,numx+1+xn);
sort(numy+1,numy+1+yn);
for(int i=1;i<=n;i++){
a[i].x=lower_bound(numx+1,numx+1+xn,a[i].x)-numx; //离散坐标
a[i].y=lower_bound(numy+1,numy+1+yn,a[i].y)-numy;
a[i].xx=lower_bound(numx+1,numx+1+xn,a[i].xx)-numx;
a[i].yy=lower_bound(numy+1,numy+1+yn,a[i].yy)-numy;
}
sort(a+1,a+1+n);
cdq(1,n);
for(int i=1;i<=n;i++) ans+=a[i].ans; //统计答案
write(ans);
}