对于多维偏序问题,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分治统计即可。。。