BZOJ 3261 陌上花开 cdq分治

给出 n ≤ 1 e 5 n\leq1e5 n1e5个三元组 ( a i , b i , c i ) (a_i,b_i,c_i) (ai,bi,ci),满足三元组 i i i比三元组 j j j美丽的条件是 a i > a j , b i > b j , c i > c j a_i>a_j,b_i>b_j,c_i>c_j ai>aj,bi>bj,ci>cj,然后求问比 i i i朵花美丽的的数量各是多少。
三维偏序。先对 x x x排序,考虑左区间和右区间的时候,再对 y y y排序,对于右边 y y y,用树状数组维护所有比 y y y小的那一部分的 z z z

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const ll INF=LONG_LONG_MAX;
const int N=1e5+5; 
const int M=2e5+2;
int ans[N]; 
struct node{ int x,y,z,cnt,ans; }a[N];
bool cmpx(node a,node b) {
	if(a.x!=b.x) return a.x<b.x;
	if(a.y!=b.y) return a.y<b.y;
	return a.z<b.z;
}
bool cmpy(node a,node b) {
	if(a.y!=b.y) return a.y<b.y;
	return a.z<b.z;
}
struct BIT{
	int tr[M];
	int n;
	int lowbit(int x) {
		return x&(-x);
	}
	void add(int x,int k) {
		while(x<=n) {
			tr[x]+=k;
			x+=lowbit(x);	
		}
	}
	int query(int x) {
		int sum=0;
		while(x>0) {
			sum+=tr[x];
			x-=lowbit(x);
		}
		return sum;
	} 
}Tree;
void CDQ(int l,int r) {
	if(l==r) {
		a[l].ans+=a[l].cnt-1;
		return;
	}
	int mid=(l+r)>>1;
	CDQ(l,mid);CDQ(mid+1,r);
	sort(a+l,a+1+mid,cmpy);
	sort(a+mid+1,a+r+1,cmpy); 
	int j=l;
	for(int i=mid+1;i<=r;i++) {
		for(;a[j].y<=a[i].y&&j<=mid;j++) 
			Tree.add(a[j].z,a[j].cnt);
		a[i].ans+=Tree.query(a[i].z);
	}
	for(int i=l;i<=j-1;i++) Tree.add(a[i].z,-a[i].cnt);
}
int main() {
	int n,k;
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++) {
		scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
		a[i].ans=1;
	}
	sort(a+1,a+1+n,cmpx);
	int tot=0;
	for(int i=1;i<=n;i++) {
		if(i!=1&&a[i-1].x==a[i].x&&a[i-1].y==a[i].y&&a[i-1].z==a[i].z) a[tot].cnt++;
		else a[++tot]=a[i],a[tot].cnt=1;
	}
	Tree.n=k; 
	CDQ(1,tot);
	for(int i=1;i<=tot;i++) ans[a[i].ans]+=a[i].cnt;
	for(int i=1;i<=n;i++) printf("%d\n",ans[i]);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值