题目简意
有n个同学,每个同学有a,b,c三个数(c=a+b)
现在,有m次询问,每次给你三个数A,B,C问你满足a>=A,b>=B,c>=C的同学的人数
一道明显的三维偏序问题,只是空间把主席树卡了(别问我为什么知道qwq)
所以,这里我们就要打空间复杂度更小的cdq分治
我们先考虑下,怎么做题,因为我们肯定不能对每次询问都单独的做一次cdq分治,这样时间复杂度会原地爆炸,所以,我们可以考虑把所有询问存下来,一起做
我们可以把每个询问看做一个学生,这样,我们只需要求出比这些“学生”三个属性都大的学生(不包括询问产生的“学生”)的个数即可
那么, 我们就可以直接上cdq分治。
我们先按a由大到小排序(如果相等,将“学生”放后面,以保证可以询问的时候,符合条件的都添加好了)
然后,我们再在cdq分治中,按b由大到小做归并排序,同时,因为我们只需要计算左边区间对右边区间的贡献,所以,我们按顺序,将左边区间的所有学生(同样不包括询问)加入一个数据结构(我是权值线段树),对于右边区间,我们对所有“学生”进行查询操作即可~
需要注意的是,为了方便进行值的查询,我们最好先将数据进行离散化(反正只需要知道大小关系即可)
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+1;
int laz[N<<2],W[N<<2];
struct node{
int a,b,c,num;
}q[N<<1];
struct lsh{
int x,w;
}p[N<<1];
int ans[N];
inline bool kkk(lsh x,lsh y){
return x.w<y.w;
}
inline bool ttt(node x,node y){
return x.a!=y.a?x.a>y.a:x.num<y.num;
}
inline void down(int now,int l,int r){
if(laz[now]){
laz[now]=0;
if(l==r){
return;
}
W[now<<1]=W[now<<1|1]=0;
laz[now<<1]=laz[now<<1|1]=1;
}
}
inline void insert(int now,int l,int r,int x){
down(now,l,r);
++W[now];
if(l==r){
return;
}
int mid=(l+r)>>1;
if(x<=mid){
insert(now<<1,l,mid,x);
}else{
insert(now<<1|1,mid+1,r,x);
}
}
inline int find(int now,int l,int r,int lc,int rc){
down(now,l,r);
if(lc<=l&&r<=rc){
return W[now];
}
int mid=(l+r)>>1,res=0;
if(lc<=mid){
res+=find(now<<1,l,mid,lc,rc);
}
if(rc>mid){
res+=find(now<<1|1,mid+1,r,lc,rc);
}
return res;
}
int n,Q,tot;
node a[N];
inline bool ppp(node x,node y){
return x.b!=y.b?x.b>y.b:x.num<y.num;
}
inline void cdq(int l,int r){
if(l==r){
return;
}
int mid=(l+r)>>1,al=0;
cdq(l,mid),cdq(mid+1,r);
//对答案加上左边对右边的贡献即可
//两边已按1.q[i].b,2.q[i].num由大到小排序
W[1]=0,laz[1]=1;//clear
int L=l,R=mid+1;//两边指针
while(L<=mid&&R<=r){
if(ppp(q[L],q[R])){
//将q[L]放入
if(!q[L].num){
insert(1,1,n,q[L].c);
}
a[++al]=q[L++];
}else{
if(q[R].num){
ans[q[R].num]+=find(1,1,n,q[R].c,n);
}
a[++al]=q[R++];
}
}
while(L<=mid){
if(!q[L].num){
insert(1,1,n,q[L].c);
}
a[++al]=q[L++];
}
while(R<=r){
if(q[R].num){
ans[q[R].num]+=find(1,1,n,q[R].c,n);
}
a[++al]=q[R++];
}
for(int i=l;i<=r;++i){//排序完毕~
q[i]=a[i-l+1];
}
}
int main(){
scanf("%d%d",&n,&Q);
for(int i=1;i<=n;++i){
scanf("%d%d",&q[i].a,&q[i].b);
q[i].c=q[i].a+q[i].b;q[i].num=0;
}
for(int i=1;i<=Q;++i){
scanf("%d%d%d",&q[n+i].a,&q[n+i].b,&q[n+i].c);
q[n+i].num=i;
}
//离散化
n=n+Q;
for(int i=1;i<=n;++i){
p[i].x=i,p[i].w=q[i].a;
}
sort(p+1,p+n+1,kkk);
q[p[1].x].a=tot=1;
for(int i=2;i<=n;++i){
if(p[i].w!=p[i-1].w){
++tot;
}
q[p[i].x].a=tot;
}
for(int i=1;i<=n;++i){
p[i].x=i,p[i].w=q[i].b;
}
sort(p+1,p+n+1,kkk);
q[p[1].x].b=tot=1;
for(int i=2;i<=n;++i){
if(p[i].w!=p[i-1].w){
++tot;
}
q[p[i].x].b=tot;
}
for(int i=1;i<=n;++i){
p[i].x=i,p[i].w=q[i].c;
}
sort(p+1,p+n+1,kkk);
q[p[1].x].c=tot=1;
for(int i=2;i<=n;++i){
if(p[i].w!=p[i-1].w){
++tot;
}
q[p[i].x].c=tot;
}
//三维偏序
sort(q+1,q+n+1,ttt);
//先按A由大到小排序
cdq(1,n);
for(int i=1;i<=Q;++i){
printf("%d\n",ans[i]);
}
return 0;
} 
京公网安备 11010502036488号