首页 > 其他分享 >【博客】CDQ分治

【博客】CDQ分治

时间:2024-03-19 16:34:48浏览次数:27  
标签:偏序 树状 int 分治 mid 博客 CDQ

CDQ分治

前言

CDQ分治是一种分治

CDQ分治是一种特殊的分治思想

可以用于跟点对有关的问题

还有其他用处......(目前不会)


算法流程

一般来说,cdq 分治是通过如下结构进行分治

一共分为三步:

  1. 找到当前区间\([l,r]\)中点\(mid\)
  2. 递归处理左右区间\([l,mid]\),\([mid+1,r]\)
  3. 计算左区间对右区间的贡献

比如归并排序求逆序对

二维偏序

将序列归并排序,在合并的时候计算左对右的贡献

这个过程就可以看作CDQ分治的思想

#include<bits/stdc++.h>
using namespace std;
const int N=5e5+5;
int n,a[N],b[N],ans;
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,now=l;//i,j表示左右指针,now表示b数组的指针
	while(i<=mid&&j<=r){
		if(a[i]<=a[j])b[now++]=a[i++];//不产生贡献
		else{//产生贡献
			b[now++]=a[j++];
			ans+=mid-i+1;//计算贡献
		}
	}//可以看到跟归并排序一样 只是多了一个计算贡献 
     //这就是归并排序求逆序对的过程 可以看作是CDQ分治的思想
	while(i<=mid)b[now++]=a[i++];
	while(j<=r)b[now++]=a[j++];
	for(int i=l;i<=r;i++)a[i]=b[i];
	return;
}
int main(){
	scanf("%lld",&n);
	for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
	cdq(1,n);
	printf("%lld",ans);
	return 0;
}

再增加一维变成三维偏序

三维偏序是CDQ分治的经典问题

先用sort按x排序 消除第一维的影响

然后将序列拆分 按y归并排序

合并的时候利用树状数组计算贡献

详细来说计算贡献的过程是

维护左右区间指针\(i,j\)

合并时我们把所有\(y_i<y_j\)的点

全部插入到树状数组里。

此时只要查询树状数组里有多少个点的\(z\)值是小于\(z_j\)的即可

也就是\(z_j\)的前缀和

void Init(int x)//清空树状数组
{
    for(;x<=s;x+=x&(-x))//s是值域
        if(f[x]!=0) f[x]=0;
        else break;
    return;
}
void Insert(int x,const int &v)//单点插入
{
    for(;x<=s;x+-=x&(-x)) f[x]+=v;
    return ;
}
int Query(int x)//查询前缀和
{
    int res=0;
    for(;x;-=x &-x) res+=f[x];
    return res;
}
void CdqSolve(const int &l,const int &r)
{
    if(l==r) return;
    int mid=l+r>>1,idx1=l,idx2=mid+1;
    CdqSolve(l,mid);
    CdqSolve(mid+1,r);
    //先分治左右区间 合并时计算贡献
    for(int i=l;i<=r;i++)
    {
        if(idx2>r || idx1<=mid && a[idx1]>a[idx2])
        {
            t[i]=a[idx1++];
            Insert(t[i].z,t[i].cnt);//左区间的插入树状数组
        }
        else
        {
            t[i]=a[idx2++];
            t[i].sum+=Query(t[i].z);//右区间的查询前缀和
        }
    }
    for(int i=l;i<=r;i++)
    {
        a[i]=t[i];
        Init(a[i].z);//清空树状数组
    }
    return;
}

再增加一维变成四维偏序。。。

好像要用CDQ分治套CDQ分治

也是坑 以后再填


附例题

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

P4169 [Violet] 天使玩偶/SJY摆棋子

大概题意是求当前点A曼哈顿距离最小的点B(K-D树板子)

先只考虑左下方的点

需要满足\(B_x<A_x,B_y<A_y\)

求\(B_x+B_y\)的最大值

每个点有三维 时间 x y

时间输入时就排好了

x归并排序处理 y树状数组

跟三维偏序一样

整个平面翻转三次

每次都这样处理

所有点就都处理到了


引用来源

【学习笔记】cdq分治 - trsins

CDQ 分治 - OI Wiki (oi-wiki.org)

侵删

标签:偏序,树状,int,分治,mid,博客,CDQ
From: https://www.cnblogs.com/zysssss/p/18083290

相关文章

  • 【博客】顺序结构
    顺序结构概念程序设计要从最简单的地方开始学习,由浅入深,直至掌握。所以要重视基础训练。我们编写计算机程序,将一个任务分解成一条一条的语句,计算机会按照顺序一条一条的执行这些语句,这就是顺序结构程序设计。举个栗子:老师给你留了寒假作业,你现在要一项一项地完成,于是你写下......
  • 【博客】分块
    分块前言顾名思义分块就是将要维护的数据分成多个块来进行操作涉及整块的直接在块上操作涉及块中的暴力操作暴力即优雅分块是在线算法一般跟区间有关系算法如果一个序列长度为\(n\)我们一般取\(\sqrt{n}\)为一个块的长度这样块的数量也是\(\sqrt{n}\)原理如下设......
  • 【博客】左偏树
    左偏树前言左偏树是一棵向左偏的树左偏树是一种能在\(O(\logn)\)之内完成合并的可并堆长这样我们常用左偏树完成以下操作在指定集合中插入一个元素查询集合中最高优先级的元素删除集合中最高优先级的元素删除指定元素合并两个集合性质首先我们要知道左偏树的......
  • 【博客】K-D树
    K-D树前言kd-tree(k-dimensional树的简称),是一种对k维空间中的实例点进行存储以便对其进行快速检索的树形数据结构。主要应用于多维空间关键数据的搜索(如:范围搜索和最近邻搜索)好像跟没说一样K-D树其实是每个结点为K维数值点的二叉树每个结点将某一维划分成两部分一部分为左......
  • 【博客】【入门级】递归
    递归有部分结论代码题目来自网络在文后有链接侵删前言什么是递归?函数反复调用自身即是递归举个栗子递归我在这篇博客里写了这篇博客的链接像不像套娃举个正经栗子比如我们算\(n\)的阶乘\(f(n)\)(阶乘就是\(1*2*3*4*...*n\))以\(f(6)\)为例\(f(6)\)=>\(6\)*$......
  • 新电脑 个人博客迁移
    安装和配置所需要的软件安装Git客户端,安装过程省略,一般默认下一步    下载地址:Git客户端    这个无脑下一步即可无需配置安装nodeJS,安装过程省略,一般默认下一步    下载地址:nodeJS    配置看这位大佬教程:地址拷贝个人博客文件夹中,部......
  • 将博客搬至CSDN
    New·Object将博客搬至CSDN在数字时代的浪潮中,我始终如一地维护着自己的一方网络空间。从最初的个人网站到现在的CSDN博客,每一次的变迁都记录着我的成长与变化。今天,我想和大家分享一下将博客搬迁至CSDN的决定背后的故事,以及这个决定给我带来的一系列连锁反应。记得最初,我的博......
  • 介绍分治算法
    分治算法是一种将问题划分成多个更小的子问题,并且分别解决这些子问题的策略。它通常包含三个步骤:分解(Divide):将原始问题划分成若干个更小的子问题。这个步骤可以使用递归实现,每次递归处理的子问题规模都要比原始问题小。解决(Conquer):递归地解决各个子问题,如果问题规模足够小,......
  • 推荐一个博客园皮肤:awescnb-theme-geek
    参考文章:我的所有做法都是参考本篇文章1.安装主题首先进入到博客后台设置:1.设置皮肤为customer,并且打开JS权限2.勾选禁用模板默认CSS3.复制粘贴配置代码(共三处)页面定制CSS代码#loading{bottom:0;left:0;position:fixed;right:0;top:0;z-index:9999;background-co......
  • 一元三次方程(分治法)
    目录题目描述分治法思想介绍分治思路我的代码总结与展望一元三次方程求解【题目描述】形如:这样的一个一元三次方程。给出该方程中各项的系数(a,b,c,d均为实数),并约定该方程存在三个不同实根(根的范围在−100至100之间),且根与根之差的绝对值≥1。要求由小到大依次在同一......