cdq分治:从归并到cdq套cdq

感谢 mlystdcall 的透彻讲解

本文里没有的代码可以去这里查看


前置芝士

cdq分治可以用来解决多维偏序问题

优点:代替复杂数据结构,代码好写(类似归并排序),常数小

缺点:必须离线

重要优点:分治过程中区间的划分可以把数值的比较转化为看看是在左区间还是右区间,省去了一维比较的过程,实现了降维打击

重要原则:cdq分治归根到底是分治,只用考虑分治后左边对右边的影响,其他的都是递归下去的子问题

原则不懂可以先记住,边看边理解


二维偏序

例:给定N个有序对(a[1],b[1]),(a[2],b[2]),......,(a[n],b[n]),求对于其中的每个的(a[i],b[i]),满足a[j]<a[i]且b[j]<b[i]的有序对(a[j],b[j])有多少个?

逆序对问题,换了个马甲而已。

各种数据结构都能水过去

这里的二维很显然,就是一个a,一个b

建议用归并排序练习一下

排序前位置递增,排序后大小递增,在排序的时候统计逆序对。

归并是cdq的雏形,归并过程中统计左边对右边造成了多少影响这个操作,就是cdq分治

#include<iostream>
#include<cstdio>
using namespace std;
int n;
int a[500001],b[500001];
long long ans=0;
void fenzhi(int l,int r)
{
	if(l==r)return;
	int mid=(l+r)>>1;
	fenzhi(l,mid);fenzhi(mid+1,r);
	int i,j,k;
	i=k=l;j=mid+1;
	while(i<=mid&&j<=r)
	{
		if(a[i]<=a[j])b[k++]=a[i++];
		else
		{
			b[k++]=a[j++];
			ans=ans+mid-i+1;//统计左边对右边造成了多少影响 cdq雏形
		}
	}
	while(i<=mid)b[k++]=a[i++];
	while(j<=r)b[k++]=a[j++];
	for(int i=l;i<=r;++i)a[i]=b[i];
}
int main()
{
	cin>>n;
	for(int i=1;i<=n;++i)scanf("%d",&a[i]);
	fenzhi(1,n);
	cout<<ans;
	return 0;
} 

带修改的类二维偏序

例:
有一个n个元素的序列,初始值全部为0,有两种操作:

操作1:格式为1 x k,把位置x的元素加上k。

操作2:格式为2 x y,求出区间[x,y]内所有元素的和。

P3374 【模板】树状数组 1

各种数据结构都能水过去

用cdq怎么做?

先找二维分别是啥

第一维是时间顺序(操作顺序),很容易被忽略

第二维是操作(询问可以用前缀和的思想拆分为两个位置)的位置

归并排序前时间递增,排序后位置递增,排序中统计。

这里详细讲一下。

归并的时候将l ~ r分为了l ~ mid(简称L)和mid + 1 ~ r(简称R)两块。

一个修改(设为X)怎么才能对一个询问(设为Y)产生影响?X的时间和位置都比Y靠前

L里的时间都比R早,L里边已经按照位置排好序了(但时间是乱的),R也一样。

双指针对L和R的位置处理一下就行了,顺便统计。

三维偏序

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

模板题

一维排序,二维cdq,三维树状数组

你也可以试试套一下别的

建议看着代码理解

代码看这里

四维偏序/cdq套cdq

例:给定n个有序四元组(a,b,c,d),求对于每一个四元组(A,B,C,D),有多少个四元组(a,b,c,d)满足a<A && b<B && c<C && d<D。

其实就是三维偏序加了一维

套娃开始了

其实我们可以把这里的(c,d)看做三维偏序里的(c),那么刚才的树状数组就要换成能维护二维信息的数据结构,空间&时间复杂度爆炸

我们思考一下,cdq优点有哪些?它能把具体的数值变成L和R的区分,省去了比较的过程。我们以L和R区分为基础(此时就省去了一维),再处理剩下的几维。

按照这个思路,我们cdq的时候其实就是分为了(aL,b,c,d)和(aR,b,c,d),我们顺便记录一下每个元素按照a是属于aL还是属于aR

我们把这个复制一遍,按照b排序(此时a的乱的,但是根据a带有L或R的标记),我们顺便记录一下每个元素按照b是属于bL还是属于bR

此时每个元素就是分为了(aL/aR,bL/bR,c,d)

要是想造成贡献,只能是(aL,bL,c,d)对(aR,bR,c,d)造成的

然后c这一维双指针,d这一维树状数组


练习题:
P3810 【模板】三维偏序(陌上花开)三维偏序
P5459 [BJOI2016]回转寿司 题解
P4093 [HEOI2016/TJOI2016]序列
P4169 [Violet]天使玩偶/SJY摆棋子
[HZOI 2016]偏序 COGS 2479 四维偏序
[bzoj2989&4170: 数列]

posted @ 2021-07-20 19:10  wljss  阅读(335)  评论(0编辑  收藏  举报