CDQ分治

思想就是分治!

然后就是每次二分区间,然后在分治统计左右区间之后,考虑统计跨越左右区间的数对。

给个模板题 陌上花开

我们对于这个三维偏序问题,可以考虑CDQ分治。

先对于原序列按照a,b,c排序,这样保证a的单调增。

然后分治,对于每个小区间按照b,a,c排序,这样在右边区间的a大于左边区间的前提下,我们满足b单调增。我们枚举j区间选取的元素,然后取移动指针i保证i位置上的b小于j位置上的b,把i位置上的c加入树状数组。每个j在树状数组上统计一遍答案。这就是全过程。

但是本题有一个问题,它有相同的元素,分治的时候会统计少。

但是我们可以合并相同的元素,就可以了。

会CDQ分治了吗?上代码就懂了。

code:

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define file(a) freopen(#a".in","r",stdin),freopen(#a".out","w",stdout)
inline int read(){
	int s=0,f=1;char ch=getchar();
	while(ch<'0'||'9'<ch) {if(ch=='-') f=-1;ch=getchar();}
	while('0'<=ch&&ch<='9') {s=s*10+(ch^48);ch=getchar();}
	return s*f;
}
const int MAXN=2e5+3;
const int N=1e5+3;
int num;
struct Bit{
	int c[MAXN];
	inline void add(int x,int k){
		for(;x<=num;x+=(x&-x) ) c[x]+=k; 
	}
	inline int find(int y){
		int res=0;
		for(;y;y-=(y&-y) ) res+=c[y];
		return res;
	}
}c;
int n;
struct node{
	int a,b,c,cnt,ans;
	inline friend bool operator ==(node x,node y){
		return (x.a==y.a and x.b==y.b and x.c==y.c);
	}
	inline friend bool operator !=(node x,node y){
		return !(x==y);
	}
}f[N],p[N];
bool cmp(node x,node y){
	if(x.a==y.a){
		if(x.b==y.b){
			return x.c<y.c;
		}
		return x.b<y.b;
	}
	return x.a<y.a;
}
bool cmp2(node x,node y){
	if(x.b==y.b){
		if(x.a==y.a){
			return x.c<y.c;
		}
		return x.a<y.a;
	}
	return x.b<y.b;
}
int ans[N];
void cdq_solve(int l,int r){
	if(l==r) return;
	int mid=(l+r)>>1;
	cdq_solve(l,mid);cdq_solve(mid+1,r);
	sort(p+l,p+mid+1,cmp2);
	sort(p+mid+1,p+r+1,cmp2);
	int i=l;
	for(int j=mid+1;j<=r;++j){
		while(i<=mid and p[i].b<=p[j].b){
			c.add(p[i].c,p[i].cnt);++i;
		}
		p[j].ans+=c.find(p[j].c);
	}
	for(int k=l;k<i;++k) c.add(p[k].c,-p[k].cnt);
}
int main(){
	//file(a);
	n=read();num=read();
	for(int i=1;i<=n;++i){
		f[i].a=read();
		f[i].b=read();
		f[i].c=read();
	}
	sort(f+1,f+n+1,cmp);
	int cnt=1;
	int num=n;n=0;
	for(int i=1;i<=num;++i){
		if(f[i]!=f[i+1]){
			p[++n]=f[i];
			p[n].cnt=cnt;
			p[n].ans=0;
			cnt=1;
			//printf("%d %d %d %d\n",p[n].a,p[n].b,p[n].c,p[n].cnt);
		}else{
			++cnt;
		}
	}
	cdq_solve(1,n);
	for(int i=1;i<=n;++i){
		ans[p[i].cnt+p[i].ans-1]+=p[i].cnt;
	}
	for(int i=0;i<num;++i){
		printf("%d\n",ans[i]);
	}
	return 0;
}
posted @ 2022-02-24 11:46  cbdsopa  阅读(33)  评论(0编辑  收藏  举报