CDQ分治 经典三维偏序P3810

二维偏序,第一维排序,第二维树状数组或CDQ分治。

三维偏序,第一维排序,第二维CDQ分治,第三位CDQ分治或树状数组。

感觉树状数组好写,常数还小点,能用树状数组尽量用。

//KX
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
//unordered_map<int,int>mp;
const int M= 1e5+7;
struct node
{
	int a,b,c;
	int v,id,ans;
}a[M],b[M];
int ans[M],c[2*M];
const int N = 2e5;
bool cmp1(node a,node b)
{
	if(a.a==b.a&&a.b==b.b)return a.c<b.c;
	if(a.a==b.a)return a.b<b.b;
	return a.a<b.a;
}
bool cmp2(node a,node b)
{
	
	if(a.b==b.b)return a.c<b.c;
	return a.b<b.b;
}
void add(int x,int d)
{
	while(x<=N)
	{
		c[x]+=d;
		x+=x&(-x);
	}
}
int qu(int x)
{
	int ret=0;
	while(x)
	{
		ret+=c[x];
		x-=x&(-x);
	}
	return ret;
}
void merge(int l,int r)
{
	if(l==r)return ;
	int m=(l+r)/2;
	merge(l,m),merge(m+1,r);
	sort(b+l,b+m+1,cmp2);
	sort(b+m+1,b+r+1,cmp2);
	int t1=l,t2=m+1;
	while(t2<=r)
	{
		while(t1<=m&&b[t1].b<=b[t2].b)add(b[t1].c,b[t1].v),t1++;
		b[t2].ans+=qu(b[t2].c),t2++;
	}
	for(int i=l;i<t1;i++)//注意 有可能while循环t1没到m,所以这里上限是t1-1. 
		add(b[i].c,-b[i].v);
}
int main()
{
	int n,k;
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++) 
		scanf("%d%d%d",&a[i].a,&a[i].b,&a[i].c),a[i].id=i,a[i].v=1;
	sort(a+1,a+1+n,cmp1);
	int sz=0;
	a[0].a=a[0].b=a[0].c=0;
	for(int i=1;i<=n;i++)
	{
		if(a[i].a==a[i-1].a&&a[i].b==a[i-1].b&&a[i].c==a[i-1].c)b[sz].v++;
		else b[++sz]=a[i],b[sz].id=i;
	}
	merge(1,sz);
	for(int i=1;i<=sz;i++)
	{
	//	printf("i:%d   ans:%d   v:%d          ::  %d   %d  %d\n",i,b[i].ans,b[i].v,b[i].a,b[i].b,b[i].c); 
		ans[b[i].ans+b[i].v-1]+=b[i].v;//按照题意算贡献,别忘了把重复元素相互间的贡献概念算出来 
	} 
		
	for(int i=0;i<n;i++)
	printf("%d\n",ans[i]);
   	return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值