CDQ分治 模板

例题

Link.

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long

int n,k,N,ans[2000005];
struct zz{
	int x,y,z,ans,tot;
}a[100005],b[100005];
bool cmp(zz x,zz y){ return x.x==y.x?(x.y==y.y?x.z<y.z:x.y<y.y):x.x<y.x; }		//排序时处理第一维相同,后两位不同的情况。 
bool smp(zz x,zz y){ return x.y==y.y?x.z<y.z:x.y<y.y; }

int Lowbit(int x){	return x&(-x);}
struct Bit_Tree{
	ll bit[4000005];
	int Lowbit(int x){ return x&(-x); }
	void Insert(int x,ll val){ for(int i=x;i<=k;i+=Lowbit(i)) bit[i]+=val; }
	ll Find(int x){ ll ans=0; for(int i=x;i;i-=Lowbit(i)) ans+=bit[i]; return ans; }
}T;

void CDQ(int l,int r){
	if(r<=l) return ; 
	int mid=(l+r)>>1;
	CDQ(l,mid),CDQ(mid+1,r);						//分治 
	sort(a+l,a+mid+1,smp),sort(a+mid+1,a+r+1,smp);  //对于上一次的序列排序,这样就不用在中间双指针排序了,因为树状数组,所以也没有加复杂度。 
	int p=l,q=mid+1;								//前半列和后半列的开头。 
	while(q<=r){
		while(p<=mid&&a[p].y<=a[q].y) T.Insert(a[p].z,a[p].tot),p++;	//答案要求三维都大,而我排序的是三维都小的情况,所以前半列对后半列产生贡献。 
		a[q].ans+=T.Find(a[q].z);q++;
	}
	for(int i=l;i<=p-1;i++) T.Insert(a[i].z,-a[i].tot);					//p-1是因为p的这位是不满足条件的,退了while。 
}

int main(){
	cin>>N>>k;
	for(int i=1;i<=N;i++) scanf("%d%d%d",&b[i].x,&b[i].y,&b[i].z);
	sort(b+1,b+N+1,cmp);
	for(int i=1;i<=N;i++){
		int now=1;
		while(b[i].x==b[i+1].x&&b[i].y==b[i+1].y&&b[i].z==b[i+1].z) now++,i++;		//相同的*在一起。 
		n++,a[n]=b[i],a[n].tot=now;
	}
	CDQ(1,n);
	for(int i=1;i<=n;i++) ans[a[i].ans+a[i].tot-1]+=a[i].tot;
	for(int i=0;i<N;i++) printf("%d\n",ans[i]);
	return 0;
}
posted @ 2022-02-12 08:53  To_Heart  阅读(3)  评论(0编辑  收藏  举报  来源