三维偏序(陌上花开)[模板]

这就是个三维的归并排序…

初始排序消掉一维 ( a ) (a) (a)

归并排序消掉一维 ( b ) (b) (b)

树状数组解决一维 ( c ) (c) (c)

当然这只是模板不是讲解,想看讲解移步全是讲解

这篇好像也不错

#include <bits/stdc++.h>
using namespace std;
const int maxn=3e5+10;
struct p{
	int a,b,c,cnt,ans;
}s1[maxn],s2[maxn];
int n,k,top,sumn[maxn],su[maxn];
bool com1(p q,p w){
	if( q.a!=w.a )	return q.a<w.a;
	if( q.b!=w.b )	return q.b<w.b;
	return q.c<w.c;
}
bool com2(p q,p w){
	if( q.b!=w.b )	return q.b<w.b;
	return q.c<w.c;
}
int lowbit(int x){ return x&(-x); }
void add(int x,int s){
	for(;x<=k;x+=lowbit(x) )	sumn[x]+=s;
}
int ask(int x){
	int ans=0;
	for(;x;x-=lowbit(x) )	ans+=sumn[x];
	return ans;
}
int query(int x)
{
	int sum=0;
	while(x)
	{
		sum+=sumn[x];
		x-=lowbit(x);
	}
	return sum;
}//求单点前缀和
void cdq(int l,int r)
{
	if( l==r )	return;
	int mid=l+r>>1;
	cdq(l,mid); cdq(mid+1,r);
	sort(s2+l,s2+mid+1,com2);
	sort(s2+mid+1,s2+r+1,com2);
	int j=l;
	for(int i=mid+1;i<=r;i++)
	{
		while( j<=mid&&s2[i].b>=s2[j].b)//j还可以为i做出贡献,j往后挪
		{
			add( s2[j].c,s2[j].cnt );
			j++;
		}
		s2[i].ans+=ask( s2[i].c ); 
	}
	for(int i=l;i<j;i++)	add( s2[i].c,-s2[i].cnt);
}
int main()
{
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d%d",&s1[i].a,&s1[i].b,&s1[i].c);
		s1[i].cnt=1,s1[i].ans=0;
	}
	sort(s1+1,s1+1+n,com1);
	s2[++top]=s1[1];
	for(int i=2;i<=n;i++)
	{
		if( s1[i].a==s1[i-1].a&&s1[i].b==s1[i-1].b&&s1[i].c==s1[i-1].c )	s2[top].cnt++;
		else	s2[++top]=s1[i];
	}
	cdq(1,top);
	for(int i=1;i<=top;i++)
		su[ s2[i].ans+s2[i].cnt-1 ]+=s2[i].cnt;
			//算上元素内部的贡献s2[cnt]-1 
	for(int i=0;i<n;i++)	printf("%d\n",su[i] );
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值