陌上花开 Solution

本文深入探讨了CDQ分治算法在解决特定类型问题上的应用。通过实例讲解了如何利用CDQ分治来消除多维度限制,实现高效的数据处理。文章提供了详细的代码示例,帮助读者理解算法的具体实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:有 n n n个元素,第 i i i个元素有 a i , b i , c i a_i,b_i,c_i ai,bi,ci三个属性,设 f i f_i fi表示满足 a i ≥ a j , b i ≥ b j , c i ≥ c j a_i\geq a_j,b_i\geq b_j,c_i\geq c_j aiaj,bibj,cicj j j j的数量。对于 d ∈ [ 0 , n ) d\in [0, n) d[0,n),求 f i = d f_i=d fi=d的数量。
考虑 c d q cdq cdq分治,静态排序消除一维,然后就可以用 c d q cdq cdq消除一维,最后一维有许多的做法,详细介绍一下再套一个 c d q cdq cdq的。
其实 c d q cdq cdq可以一直套,只要记录一下每一层这个数是否有能力产生贡献。
也就是说,在上一层 c d q cdq cdq中,归为右边的数记它的权值为 1 1 1,只有权值为 1 1 1的数,才能在下一层 c d q cdq cdq中产生影响和计算答案。
c o d e : code: code:

#include <bits/stdc++.h>
#define regi register int
int n,k;
int ans[1000000];
int pts[1000000];
struct axe{
	int x;
	int y;
	int z;
	int id;
	int val;
	int amount;
}a[1000000],b[1000000],c[1000000],tmp[1000000];
bool cmp(axe x,axe y){
	return x.x==y.x?(x.y==y.y?x.z<y.z:x.y<y.y):x.x<y.x;
}
void calc(int l,int r){
	if(l==r)
	  return;
	int mid=l+r>>1;
	calc(l,mid);
	calc(mid+1,r);
  int C=0;
	for(regi top=l,i=l,j=mid+1;top<=r;++top){
		if((j>r||b[i].z<=b[j].z)&&i<=mid){
		  c[top]=b[i++];
		  C+=c[top].val*c[top].amount;
		}
		else{
			c[top]=b[j++];
			if(!c[top].val)
				ans[c[top].id]+=C;
		}
	}
	for(regi i=l;i<=r;++i)
	  b[i]=c[i];
}
void solve(int l,int r){
	if(l==r)
	  return;
	int mid=l+r>>1;
	solve(l,mid);
	solve(mid+1,r);
	for(regi top=l,i=l,j=mid+1;top<=r;++top){
		if((j>r||a[i].y<=a[j].y)&&i<=mid){
		  b[top]=a[i++];
		  b[top].val=1;
		}
		else{
		  b[top]=a[j++];
		  b[top].val=0;
		}
	}
	for(regi i=l;i<=r;++i)
	  a[i]=b[i];
	calc(l,r);
}
main(){
	scanf("%d%d",&n,&k);
	for(regi i=1;i<=n;++i){
	  scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
	  a[i].id=i;
	}
	std::sort(a+1,a+n+1,cmp);
	tmp[1]=a[1];
	tmp[1].amount=1;
	int j=1;
  for(regi i=2;i<=n;++i){
  	if(a[i].x!=tmp[j].x||a[i].y!=tmp[j].y||a[i].z!=tmp[j].z)
  	  tmp[++j]=a[i];
  	tmp[j].amount++;
  }
  int nn=n;
  n=j;
  for(regi i=1;i<=n;++i)
    a[i]=tmp[i];
	solve(1,n);
  for(regi i=1;i<=n;++i)
    pts[ans[a[i].id]+a[i].amount]+=a[i].amount;
  for(regi i=1;i<=nn;++i)
    printf("%d\n",pts[i]);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值