CDQ分治

CDQ 分治

归并排序








来自《算法导论》。

#include<algorithm>
#include<cstdio>
const int MAXN=1e6;
int n,a[MAXN+10],l[MAXN+10],r[MAXN+10];
long long ans;
void merge(int p,int q,int s) {
	int n1=q-p+1,n2=s-q;
	for(int i=1; i<=n1; i++) l[i]=a[p+i-1];
	for(int i=1; i<=n2; i++) r[i]=a[q+i];
	l[n1+1]=r[n2+1]=2e9;
	int i=1,j=1;
	for(int k=p; k<=s; k++) {
		if(l[i]<=r[j]) a[k]=l[i++];
		else {
			ans+=n1-i+1;//求解逆序对
			a[k]=r[j++];
		}
	}
}
void msort(int p,int s) {
	if(p<s) {
		int q=(p+s)/2;
		msort(p,q);
		msort(q+1,s);
		merge(p,q,s);
	}
}
int main() {
	scanf("%d",&n);
	for(int i=1; i<=n; i++) scanf("%d",&a[i]);
	msort(1,n);
	printf("%lld\n",ans);
	return 0;
}

CDQ分治

二维偏序:模板

#include<algorithm>
#include<cstdio>
#include<iostream>
using std::sort;
const int MAXN=1e6;
int n,tree[MAXN+10],level[MAXN+10];
struct node {
	int x,y;
} a[MAXN+10];
bool cmp(node p,node q) {
	return p.x<q.x||(p.x==q.x&&p.y<q.y);
}
void Add(int x,int k) {
	for(; x<=MAXN; x+=x&-x) tree[x]+=k;
}
int Query(int x) {
	int res=0;
	for(; x; x-=x&-x) res+=tree[x];
	return res;
}
int main() {
	scanf("%d",&n);
	for(int i=1; i<=n; i++) scanf("%d %d",&a[i].x,&a[i].y);
	sort(a+1,a+1+n,cmp);
	for(int i=1; i<=n; i++) {
		int p=Query(a[i].y);
		Add(a[i].y,1);
		level[p]++;
	}
	for(int i=0; i<n; i++) printf("%d\n",level[i]);
	return 0;
}

例题 P3810 【模板】三维偏序(陌上花开)

学习完了二位偏序,我们来学习三维偏序。
我们只要保证在有一维是有序的情况下,我们就把三维偏序转化为了二维偏序。
设参数为\(a,b,c\)
先按照\(a\)参数排序,然后分治。
分治把一个区间\([l,r]\)变成\([l,mid]\)\([mid+1,r]\)
在分治内部,类似归并排序,按照\(b\)参数排序。
因为此时对于两个区间来说,\(a\)参数已经没有关系了,因为右区间的\(a\)参数不小于左区间的\(a\)参数。
那么此时考虑\(b\)参数。
把左区间和右区间合并,用双指针\(i,j\)
当遇到\(b_i \leq b_j\)时,将\(c_i\)加入树状数组。
否则,查询小于\(c_j\)的个数,贡献答案。
最后,将合并后的数组更新。
注意要清空树状数组。
然后回溯。
注意开始要去重,因为如果两朵花属性完全相等,那他们不能互相计算到答案,一朵花只能计算顺序比他小的答案。

#include<algorithm>
#include<cstdio>
#include<iostream>
using namespace std;
const int MAXN=1e5;
struct node {
	int a,b,c,id;
} p[MAXN+10],tmp[MAXN+10];
int n,k;
int c[MAXN*2+10],ans[MAXN+10],cnt[MAXN+10],d[MAXN+10];
void add(int i,int x) {
	for(; i<=k; i+=i&-i) c[i]+=x;
}
void clear(int i) {
	for(; i<=k; i+=i&-i) c[i]=0;
}
int sum(int i) {
	int ret=0;
	for(; i; i-=i&-i) ret+=c[i];
	return ret;
}
bool cmp1(node x,node y) {
	return x.a<y.a||(x.a==y.a&&x.b<y.b)||(x.a==y.a&&x.b==y.b&&x.c<y.c);
}
void cdq(int l,int r) {
	if(l==r) return ;
	int mid=(l+r)/2;
	cdq(l,mid);
	cdq(mid+1,r);
	int i=l,j=mid+1,k1=l;
	while(i<=mid&&j<=r) {
		if(p[i].b<=p[j].b) {
			add(p[i].c,cnt[p[i].id]);
			tmp[k1++]=p[i++];
		} else {
			ans[p[j].id]+=sum(p[j].c);
			tmp[k1++]=p[j++];
		}
	}
	while(i<=mid) tmp[k1++]=p[i++];
	while(j<=r) {
		ans[p[j].id]+=sum(p[j].c);
		tmp[k1++]=p[j++];
	}
	for(int i=l; i<=r; i++) {
		p[i]=tmp[i];
		clear(p[i].c);
	}
}
int main() {
	scanf("%d %d",&n,&k);
	for(int i=1; i<=n; i++) {
		scanf("%d %d %d",&p[i].a,&p[i].b,&p[i].c);
		p[i].id=i;
	}
	int m=0;
	sort(p+1,p+1+n,cmp1);
	for(int i=1; i<=n; ++i) {
		if(p[i].a!=p[m].a||p[i].b!=p[m].b||p[i].c!=p[m].c) p[++m]=p[i];
		cnt[m]++;
	}
	for(int i=1; i<=m; i++) p[i].id=i;
	cdq(1,m);
	for(int i=1; i<=m; i++) d[ans[p[i].id]+cnt[p[i].id]-1]+=cnt[p[i].id];
	for(int i=0; i<n; i++) printf("%d\n",d[i]);
	return 0;
}
posted @ 2022-08-13 13:32  s1monG  阅读(32)  评论(0编辑  收藏  举报