[AHOI2008]矩形藏宝地

解法1:

这道题显然可以转化为一个四维偏序问题的模板,即用 CDQ 套 CDQ 解决

虽然三个 log 比较劣,但是思维难度低。

考虑若矩形 \(j\) 要对矩形 \(i\) 产生贡献,即 $ j$ 包含 \(i\),需要满足\(x_{j2}>x_{i2}​,y_{j2}>y_{i2}​,x_{j1}<x_{i1},y_{j1}<y_{i1}\)

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+5;
const int K = 2e6+6;

struct Rectangle{
	int a,b,c,d,w,ans,pos;//x1,y1,x2,y2,ans是这个矩形包含的数量,pos即原位置
	bool operator <(const Rectangle& x)const{
		return a==x.a?(b==x.b?(c==x.c?d<x.d:c<x.c):(b<x.b)):a<x.a;
	}
}rec[N],tmpb[N],tmpc[N],tmp[N];
int n,m,a,b,c,d,ans;
int f[N];
struct BIT{
	int c[K<<1];
	int lowbit(int x){return -x&x;}
	void add(int x,int val){for(;x<=K;x+=lowbit(x))c[x]+=val;}
	int ask(int x){int res=0;for(;x;x-=lowbit(x))res+=c[x];return res;}
}bit;

void solvec(int l,int r){
    if(l==r)return;
    int mid=(l+r)>>1;
    solvec(l,mid);solvec(mid+1,r);
    int p1=l,p2=mid+1,ctmp=l;
    while(p1<=mid&&p2<=r){
        if(tmpb[p1].c<tmpb[p2].c){
            if(!tmpb[p1].a)bit.add(tmpb[p1].d,tmpb[p1].w);
            tmpc[ctmp++]=tmpb[p1++];
        }else{
            if(tmpb[p2].a)tmpb[p2].ans+=bit.ask(tmpb[p2].d);
            tmpc[ctmp++]=tmpb[p2++];
        }
    }
    while(p1<=mid){
        if(!tmpb[p1].a)bit.add(tmpb[p1].d,tmpb[p1].w);
        tmpc[ctmp++]=tmpb[p1++];
    }
    while(p2<=r){
        if(tmpb[p2].a)tmpb[p2].ans+=bit.ask(tmpb[p2].d);
        tmpc[ctmp++]=tmpb[p2++];
    }
    for(int i=l;i<=mid;i++)
        if(!tmpb[i].a)bit.add(tmpb[i].d,-tmpb[i].w);
    for(int i=l;i<=r;i++)
        tmpb[i]=tmpc[i];
}

void solveb(int l,int r){
    if(l==r)return;
    int mid=(l+r)>>1;
    solveb(l,mid);solveb(mid+1,r);
    int p1=l,p2=mid+1,ctmp=l;
	while(p1<=mid&&p2<=r){
		if(rec[p1].b<rec[p2].b){
			tmpb[ctmp]=tmp[ctmp]=rec[p1++];
			tmpb[ctmp++].a=0;
        }else{
            tmpb[ctmp]=tmp[ctmp]=rec[p2++];
            tmpb[ctmp++].a=1;
        }
    }
    while(p1<=mid){tmpb[ctmp]=tmp[ctmp]=rec[p1++];tmpb[ctmp++].a=0;}
	while(p2<=r){tmpb[ctmp]=tmp[ctmp]=rec[p2++];tmpb[ctmp++].a=1;}
    solvec(l,r);
    for(int i=l;i<=r;i++){
        if(tmpb[i].ans)f[tmpb[i].pos]=1;
        rec[i]=tmp[i];
    }
}

int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d%d%d",&a,&b,&c,&d);
        rec[i]={a,b,2e6-c,2e6-d,1,0,i};
    }
    sort(rec+1,rec+1+n);
    solveb(1,n);
    for(int i=1;i<=n;i++)
        ans+=f[i];
    printf("%d\n",ans);
    return 0;
}

** 解法二: **

离散化优化冗余复杂度(坐标范围 2e6)

排序维护 x2 降序,归并维护 y2 降序

现在我们保证了右上角可以包含,

接下来可以用前缀最小值BIT用 x1 的坐标,存 y1 的值

然后树状数组 ask() 与当前 y1 比较

特别需要注意的是对于 BIT 的还原顺序

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+5;
const int INF = 0x3f3f3f3f;

int ans,n,cx,cy;
int numx[N<<1],numy[N<<1];
struct Rectangle{
    int x,y,xx,yy,ans;
    bool operator<(const Rectangle&b)const{
        return xx>b.xx;
    }
}a[N],tmp[N];
struct BIT{
    int c[N<<1];
    void init(){memset(c,0x3f,sizeof(c));}
    int lowbit(int x){return -x&x;}
    void add(int x,int val){for(;x<=cx;x+=lowbit(x))c[x]=min(c[x],val);}
    int ask(int x){int res=INF;for(;x;x-=lowbit(x))res=min(res,c[x]);return res;}
    void clear(int x){for(;x<=cx;x+=lowbit(x))c[x]=INF;}
}bit;

void init(){
    bit.init();
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d%d%d",&a[i].x,&a[i].y,&a[i].xx,&a[i].yy);
        numx[++cx]=a[i].x;numx[++cx]=a[i].xx;
        numy[++cy]=a[i].y;numy[++cy]=a[i].yy;
    }
    sort(numx+1,numx+1+cx);sort(numy+1,numy+1+cy);
    for(int i=1;i<=n;i++){
        a[i].x=lower_bound(numx+1,numx+1+cx,a[i].x)-numx;
		a[i].y=lower_bound(numy+1,numy+1+cy,a[i].y)-numy;
		a[i].xx=lower_bound(numx+1,numx+1+cx,a[i].xx)-numx;
		a[i].yy=lower_bound(numy+1,numy+1+cy,a[i].yy)-numy;
    }
    sort(a+1,a+1+n);
}

void solve(int l,int r){
    if(l==r)return;
    int mid=(l+r)>>1;
    solve(l,mid);solve(mid+1,r);
    int p1=l,p2=mid+1,ctmp=l;
    while(p1<=mid&&p2<=r){
        if(a[p1].yy>a[p2].yy){
            bit.add(a[p1].x,a[p1].y);
            tmp[ctmp++]=a[p1++];
        }else{
            if(a[p2].y>bit.ask(a[p2].x))a[p2].ans=1;
            tmp[ctmp++]=a[p2++];
        }
    }
    while(p2<=r){
        if(a[p2].y>bit.ask(a[p2].x))a[p2].ans=1;
        tmp[ctmp++]=a[p2++];
    }
    for(int i=l;i<p1;i++)bit.clear(a[i].x);
    while(p1<=mid)tmp[ctmp++]=a[p1++];
    for(int i=l;i<=r;i++)a[i]=tmp[i];
}

void calc(){
    for(int i=1;i<=n;i++)
        ans+=a[i].ans;
    printf("%d\n",ans);
}

int main(){
    init();
    solve(1,n);
    calc();
    return 0;
}
posted @ 2021-03-17 13:01  _Famiglistimo  阅读(62)  评论(0编辑  收藏  举报