【陌上花开】

陌上花开,可缓缓归矣

三维偏序
可以使用\(CDQ\)分治来解决
首先考虑分治
对于要处理的区间,按照\(x\)排序,保持一维关系,分成前后两块,按\(y\)排序,那么前后两块保证的是前面那块的\(x\)小于后面那块,对于\(z\)用数据结构(树状数组好了)维护,用前面那段更新后面那段就好了

#include<iostream>
#include<cstdio>
#include<algorithm>
#define ll long long
#define N 100005
#define lowbit(x) (x & -x)

struct P{
	ll x,y,z,id;
}e[N];

ll ans[N],unq[N],f[N];
ll t[N * 2];

ll n,k;

void add(ll x,ll p){
	for(int i = x;i <= k;i += lowbit(i))
	t[i] += p;
}

int get(ll x){
	ll ans = 0;
	for(int i = x;i;i -= lowbit(i))
	ans += t[i];
	return ans;
}

bool cmp(P t,P s){
	if(t.x != s.x)
	return t.x < s.x;
	if(t.y != s.y)
	return t.y < s.y;
	return t.z < s.z;
}

bool cmp1(P t,P s){
	if(t.y != s.y)
	return t.y < s.y;
	if(t.z != s.z)
	return t.z < s.z;	
	return t.x < s.x;
}

void cdq(ll l,ll r){
	if(l == r)
	return;
	int mid = (l + r) >> 1;
	cdq(l,mid),cdq(mid + 1,r);
	std::sort(e + l,e + r + 1,cmp1);
	for(int i = l;i <= r;++i)
	if(e[i].x <= mid)
	add(e[i].z,1);
	else
	ans[e[i].id] += get(e[i].z);
	for(int i = l;i <= r;++i){
	if(e[i].x <= mid)
	add(e[i].z,-1);
//	printf("%lld %lld\n",e[i].x,ans[e[i].id]);
	}
}

int main(){
	scanf("%lld%lld",&n,&k);
	for(int i = 1;i <= n;++i)
	scanf("%lld%lld%lld",&e[i].x,&e[i].y,&e[i].z),e[i].id = i;
	std::sort(e + 1,e + n + 1,cmp);
	for(int i = 1,j;i <= n;){
		j = i + 1;
		while(j <= n && e[j].x == e[i].x && e[j].y == e[i].y && e[j].z == e[i].z)
		j ++ ;
		while(i < j)
		unq[e[i].id] = e[j - 1].id,i ++ ;
	}
	for(int i = 1;i <= n;++i)
	e[i].x = i;
	cdq(1,n);
	for(int i = 1;i <= n;++i)
	f[ans[unq[e[i].id]]] ++ ;
	for(int i = 0;i < n;++i)
	printf("%lld\n",f[i]);
} 
原文地址:https://www.cnblogs.com/dixiao/p/14575243.html