對於多維偏序問題,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分治統計即可。。。