做题记录整理分治2 P3810 【模板】三维偏序(陌上花开)(2022/9/15)

P3810 【模板】三维偏序(陌上花开)

CDQ分治,先用第一维排序,用第二维归并排序,第三维再上树状数组

#include<bits/stdc++.h>
#define for1(i,a,b) for(int i = a;i<=b;i++)
#define ll long long
#define mp(a,b) make_pair(a,b)
using namespace std;
struct node {
	int x;
	int y;
	int z;
	int cnt,ans;
} a[500005],b[500005];
int n,m,k;
int ans[500005];
int c[500005];

bool cmp1(node x,node y) { //第一维排序
	if(x.x==y.x) {
		if(x.y==y.y)return x.z<y.z;
		else return x.y<y.y;
	} else return x.x<y.x;
}

bool cmp2(node x,node y) { //第二维排序
	if(x.y==y.y)
		return x.z<y.z;
	else return x.y<y.y;
}

int lb(int x) {
	return x&(-x);
}

void xg(int x,int y) {
	while(x<=k) {
		c[x]+=y;
		x+=lb(x);
	}
}

int qh(int x) {
	int ansm=0;
	while(x) {
		ansm+=c[x];
		x-=lb(x);
	}
	return ansm;
}

void cdq(int l,int r) {//cdq分治
	if(l==r)return;
	
	int mid=(l+r)>>1;
	cdq(l,mid);
	cdq(mid+1,r);
	
	sort(b+l,b+mid+1,cmp2);
	sort(b+mid+1,b+r+1,cmp2);//第二维为关键字排序
	
	int j=l;
	for1(i,mid+1,r) {
		while(b[i].y>=b[j].y&&j<=mid) {
			xg(b[j].z,b[j].cnt);
			j++;
		}
		b[i].ans+=qh(b[i].z);
	}
	
	for1(i,l,j-1)
	xg(b[i].z,-b[i].cnt);//清空树状数组
}

int main() {
	scanf("%d%d",&n,&k);
	
	for1(i,1,n)scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
	
	sort(a+1,a+1+n,cmp1);//第一维为关键字排序
	
	int ji=0;
	for1(i,1,n) {
		ji++;
		if(a[i].x!=a[i+1].x||a[i].y!=a[i+1].y||a[i].z!=a[i+1].z) {
			b[++m].x=a[i].x;
			b[m].y=a[i].y;
			b[m].z=a[i].z;
			b[m].cnt=ji;
			ji=0;
		}
	}//去重
	
	cdq(1,m);
	
	for1(i,1,m)	ans[b[i].ans+b[i].cnt-1]+=b[i].cnt;
	
	for1(i,0,n-1)
	printf("%d\n",ans[i]);
	return 0;
}
posted @ 2022-09-15 17:33  yyx525jia  阅读(25)  评论(0)    收藏  举报