BZOJ 1935 园丁的烦恼 (cdq分治+树状数组)

对于多维偏序问题,cdq分治可以使问题维度降低一维(当然嵌套的cdq分治可以降低多维)。

所以解决多维偏序问题都可以这样做:第一维排序,中间几维cdq分治,最后一维树状数组。

本题可以认为是一个三维偏序问题

写到上面这句话时突然感觉自己脑子有坑。。。

我的做法是这样的:

第一维时间(然而事实上因为过程中没有修改,所以并没有这一维),第二维X坐标,第三维Y坐标,本题确实可以认为是一个三维偏序问题(第一维居然是做题人自己给自己的约束,剧毒。。。)

总之,如果把这题当三维偏序来做,对X坐标进行cdq分治,然后分治过程中再对Y坐标使用树状数组进行统计即可。

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define db double
#define m_p make_pair
#define p_b push_back
#define For(i,a,b) for(int i=a;i<=b;i++)
#define ls (root<<1)
#define rs ((root<<1)|1)
const int N=5e5+5;
const int M=1e7+5;
const db eps=1e-8;
const int INF=0x3f3f3f3f;
const int mod=1e7;
int n,m,cnt;
int c[M],ans[M];
int lowbit(int x){
	return x&(-x);
}
void add(int x,int z){
	while(x<M){
		c[x]+=z;
		x+=lowbit(x);
	}
}
int sum(int x){
	int res=0;
	while(x>0){
		res+=c[x];
		x-=lowbit(x);
	}
	return res;
}
void clear(int x){
	while(x<M&&c[x]!=0){
		c[x]=0;
		x+=lowbit(x);
	}
}
struct node{
	int type,x,y,id;
	bool operator<(const node &p){
		return x<p.x||x==p.x&&type<p.type;
	}
}Q[N*5],tmp[N*5];
void cdq(int l,int r){
	if(r<=l) return;
	int mid=(l+r)/2;
	cdq(l,mid);cdq(mid+1,r);
	int i=l,j=mid+1,o=l;
	while(i<=mid&&j<=r){
	//由于右边的修改不会改变左边的查询,而对右边的影响已经在下层计算过了 
	//左边的查询在下层已经查询过了
	//因此只需要考虑左边的修改对右边的影响 
		if(Q[i]<Q[j]){
			if(Q[i].type==1) add(Q[i].y,1);
			tmp[o++]=Q[i++];
		}
		else{
			if(Q[j].type==2) ans[Q[j].id]+=sum(Q[j].y);
			else if(Q[j].type==3) ans[Q[j].id]-=sum(Q[j].y);
			tmp[o++]=Q[j++];
		}
	}
	while(i<=mid){
		tmp[o++]=Q[i++];
	}
	while(j<=r){
		if(Q[j].type==2) ans[Q[j].id]+=sum(Q[j].y);
		else if(Q[j].type==3) ans[Q[j].id]-=sum(Q[j].y);
		tmp[o++]=Q[j++];
	}
	for(i=l;i<=r;i++){
		Q[i]=tmp[i];
		clear(tmp[i].y);
	}
}


int main(){
	scanf("%d %d",&n,&m);
	For(i,1,n){
		scanf("%d %d",&Q[cnt].x,&Q[++cnt].y);
		//!!!不要在第一个Q那里使用++cnt!!! 
		//据说C语言传参是从右往左的,右边的参数先执行,
		//但是最好还是别在参数处使用自增运算符 
		cout<<Q[cnt].x<<" "<<Q[cnt].y<<"\n";
		Q[cnt].y+=2,Q[cnt].x+=2;
		Q[cnt].type=1;
		
	}
	int x,y,xx,yy;
	For(i,1,m){
		scanf("%d %d %d %d",&x,&y,&xx,&yy);
		Q[++cnt].type=2,Q[cnt].x=x+1,Q[cnt].y=y+1,Q[cnt].id=i;
		Q[++cnt].type=3,Q[cnt].x=xx+2,Q[cnt].y=y+1,Q[cnt].id=i;
		Q[++cnt].type=3,Q[cnt].x=x+1,Q[cnt].y=yy+2,Q[cnt].id=i;
		Q[++cnt].type=2,Q[cnt].x=xx+2,Q[cnt].y=yy+2,Q[cnt].id=i;
	}
	cdq(1,cnt);
	for(int i=1;i<=m;i++){
		cout<<ans[i]<<"\n";
	}
    return 0;
}

在写这篇题解的时候,我突然想到,因为并没有在查询过程中另外插入一些值,所以并没有时间这一维,那么这是一个二维偏序问题,其实只需要对X坐标排序,然后对Y坐标用树状数组或cdq分治统计即可。。。

猜你喜欢

转载自blog.csdn.net/qq_38515845/article/details/89334695
今日推荐