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分治統計即可。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章