加载中…

返回上一页

CDQ分治

具体来看一个题:
陌上花开

题目描述

有 $ n $ 个元素,第 $ i $ 个元素有 $ a_i,b_i,c_i $ 三个属性,设 $ f(i) $ 表示满足 $ a_j \leq a_i $ 且 $ b_j \leq b_i $ 且 $ c_j \leq c_i $ 且 $ j \ne i $ 的 \(j\) 的数量.

对于 $ d \in [0, n) $,求 $ f(i) = d $ 的数量.

输入格式

第一行两个整数 $ n,k $,表示元素数量和最大属性值.

接下来 $ n $ 行,每行三个整数 $ a_i ,b_i,c_i $,分别表示三个属性值.

输出格式

$ n $ 行,第 $ d + 1 $ 行表示 $ f(i) = d $ 的 $ i $ 的数量.

样例

样例输入

10 3
3 3 3
2 3 3
2 3 1
3 1 1
3 1 2
1 3 1
1 1 2
1 2 2
1 3 2
1 2 1

样例输出

3
1
3
0
1
0
1
0
0
1

提示

$ 1 \leq n \leq 10^5$,$1 \leq a_i, b_i, c_i \le k \leq 2 \times 10^5 $.

对于三个数均小于当前数,我们可以使用CDQ分治来解决.

它的思想是,先按照第一维进行排序,再按照第二维进行分治,最后把第三维加入树状数组.

不想再详细写了,具体可以参考一下网上的详细解释.

给一个标程,具体里面有注释.

#include<bits/stdc++.h>
#define ll long long
#define rg register
#define maxn 100001
#define rll rg ll
using namespace std;
struct node
{
	ll a,b,c,num,ans;
}a[maxn],b[maxn];
inline bool cmp_a(node a,node b)
{
	if(a.a==b.a)
	{
		if(a.b==b.b) return a.c<b.c;
		return a.b<b.b;
	}
	return a.a<b.a;
}
inline bool cmp_b(node a,node b)
{
	if(a.b==b.b)
	{
		if(a.a==b.a) return a.c<b.c;
		return a.a<b.a;
	}
	return a.b<b.b;
}
ll cnt;
ll n,k;
ll ans[maxn];
ll c[maxn];//树状数组
#define lowbit(x) (x&-x)
inline void add(ll x,ll y)
{
	for(rll i=x;i<=k;i+=lowbit(i))
		c[i]+=y;
}
inline ll query(ll x)
{
	rll ans=0;
	for(rll i=x;i;i-=lowbit(i))
		ans+=c[i];
	return ans;
}
inline void cdqfz(ll l,ll r)
{
	if(l==r) return;
	rll mid=(l+r)>>1;
	cdqfz(l,mid);
	cdqfz(mid+1,r);
	sort(b+l,b+mid+1,cmp_b);//[l,mid+1)=[l,mid]
	sort(b+mid+1,b+r+1,cmp_b);//[mid+1,r+1)=[mid+1,r]
	rll tmp=l;
	for(rll i=mid+1;i<=r;i++)
	{
		while(b[i].b>=b[tmp].b&&tmp<=mid)
			add(b[tmp].c,b[tmp].num),tmp++;
		b[i].ans+=query(b[i].c);//求严格小于它的个数
	}
	for(rll i=l;i<=tmp-1;i++) add(b[i].c,-b[i].num);
	//清空操作
}
int main()
{
	ios::sync_with_stdio(0);
	cin>>n>>k;
	for(rll i=1;i<=n;i++) cin>>a[i].a>>a[i].b>>a[i].c;
	sort(a+1,a+n+1,cmp_a);
	for(rll i=1,num=0;i<=n;i++)
	{
		num++;//相同的项的个数
		if(a[i].a!=a[i+1].a||a[i].b!=a[i+1].b||a[i].c!=a[i+1].c)
			b[++cnt]=a[i],b[cnt].num=num,num=0;
	}
	cdqfz(1,cnt);
	for(rll i=1;i<=cnt;i++)
		ans[b[i].ans+b[i].num]+=b[i].num;
	for(rll i=1;i<=n;i++) cout<<ans[i]<<endl;
	return 0;
}
posted @ 2022-06-18 11:51  1Liu  阅读(55)  评论(0)    收藏  举报