ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CDQ分治学习笔记

2022-07-16 20:34:45  阅读:133  来源: 互联网

标签:偏序 ch int 分治 mid 笔记 CDQ 排序


CDQ 分治

\(CDQ\) 分治可以用来解决多维偏序问题

它是一个在线算法

二维偏序

给你 \(n\) 个元素,每个元素有两个属性 \(a_i\) 和 \(b_i\),定义 \(f(i)\) 表示 \(a_j\le a_i\) 且 \(b_j\le b_i\) 的元素数量

求 \(f(i)=d\) 的数量 \((d\in[0,n])\)

思路

我们可以以 \(a_i\) 为第一关键字,\(b_i\) 为第二关键字从小到大排序

排序后对于第 \(i\) 个数我们找前 \(i-1\) 个数中 \(b_j\le b_i\) 的 \(j\) 的个数

搞一个树状数组维护即可,复杂度 \(O(n\log n)\)

三维偏序

\(\to \text{模板}\leftarrow\)

三维偏序的问题无非就是在二维偏序上加了一维 \(c\)

我们考虑先按第一维 \(a\) 排序

然后第二维考虑归并排序,第三维用树状数组

我们在归并排序的时候考虑 \([l,mid]\) 对 \([mid+1,r]\) 的贡献

由于我们已经对第一维 \(a\) 排序过了,因此归并排序时无论 \(a\) 怎样被打乱,\([mid+1,r]\) 中所有元素的 \(a\) 值是不小于 \([l,mid]\) 的,第二维是 \(ok\) 的

在满足前两维均有序的条件下,我们可以用类似于二维偏序的解法搞一个树状数组统计就行了

这样的时间复杂度是 \(O(n\log^2 n)\) 的

\(p.s.\) 要对元素进行去重

code

#include<bits/stdc++.h>
using namespace std;

#define lowbit(x) x&-x

const int N=1e5+5;

inline int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}

int n,m;
int ans[N],c[N];

struct num{
	int a,b,c,w,f;
	inline bool operator < (const num A){
		return a==A.a?(b==A.b?c<A.c:b<A.b):a<A.a;
	}
}a[N],tmp[N];

inline void add(int x,int k){
	for(;x<=m;x+=lowbit(x))
		c[x]+=k;
}

inline int query(int x){
	int res=0;
	for(;x;x-=lowbit(x)) res+=c[x];
	return res;
}

inline void CDQ(int l,int r){
	if(l==r) return;
	int mid=l+r>>1;
	CDQ(l,mid),CDQ(mid+1,r);
	int i=l,j=mid+1,cnt=l-1;
	while(i<=mid&&j<=r){
		if(a[i].b<=a[j].b) add(a[i].c,a[i].w),tmp[++cnt]=a[i++];
		else a[j].f+=query(a[j].c),tmp[++cnt]=a[j++];
	}
	while(i<=mid) add(a[i].c,a[i].w),tmp[++cnt]=a[i++];
	while(j<=r) a[j].f+=query(a[j].c),tmp[++cnt]=a[j++];
	for(i=l;i<=mid;++i) add(a[i].c,-a[i].w);
	for(i=l;i<=r;++i) a[i]=tmp[i];
}

signed main(){
	n=read(),m=read();
	for(int i=1;i<=n;++i)
		a[i].a=read(),a[i].b=read(),a[i].c=read(),a[i].w=1;
	sort(a+1,a+n+1);
	int r=1;
	for(int i=2;i<=n;++i){
		if(a[i].a==a[r].a&&a[i].b==a[r].b&&a[i].c==a[r].c) ++a[r].w;
		else a[++r]=a[i];
	}
	CDQ(1,r);
	for(int i=1;i<=r;++i) ans[a[i].f+a[i].w-1]+=a[i].w;
	for(int i=0;i<n;++i) cout<<ans[i]<<endl;
}

标签:偏序,ch,int,分治,mid,笔记,CDQ,排序
来源: https://www.cnblogs.com/into-qwq/p/16485156.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有