当前位置: 首页 > news >正文

CDQ分治-学习总结篇

CDQ分治学习笔记

CDQ分治思想

我们要理解到 CDQ 分治是做什么的,CDQ 分治是一种分治算法,或者说是一种思想,其主要内容是:将序列通过递归的方式分给左右两个区间,每一个子问题只处理跨左右区间的贡献。

使用 CDQ 分治建立在排序的基础上,这也说明 CDQ 分治必须离线使用

CDQ 分治可以解决的问题:

  • 与点对有关的问题(数点 & 偏序)。
  • 将带修改 & 查询的动态问题,转化为静态问题。
  • 优化 1D / 1D 动态规划的转移。

本质上,这些问题都属于“点对之间的贡献问题”。

点对相关知识

二元关系

定义

何为二元关系(binary relation)?感性理解,二元关系就是 function<bool(T1, T2)>,比如说:

  • \(\mathbb{R}\) 上的 \(<\),即 less<double>
  • \(\mathbb{N}_+\) 上的 \(|\),即 [(int x, int y) { return y % x == 0; }]
  • 集合上的 \(\subseteq\)
  • 甚至是 \(\mathbb{Z}\) 上的奇怪关系 [(int x, int y) { return x + y >= 10; }]

注意到以上的四个例子都满足 \(T1 = T2\),事实上,这样的二元关系被称为齐次二元关系

那么我们给出数学上的标准定义:


二元关系(binary relation)

集合 \(X\) 和集合 \(Y\) 上的一个二元关系 \(R\) 定义为元组 \((X, Y, G(R))\),其中:

  • \(X\) 称为定义域(domain),
  • \(Y\) 称为值域(codomain),
  • \(G(R) \subseteq X \times Y = \{(x, y) : x \in X, y \in Y\}\) 称为二元关系 \(R\)(graph)。
    \(xRy\) 成立当且仅当 \((x, y) \in G(R)\)

特别的,若 \(X = Y\),则称该二元关系为齐次二元关系(homogeneous relation)。


下文我们所研究的二元关系,都是齐次二元关系。


直接一点就是用 \(R\) 表示二元关系(即有某种关系/ \(R\) 表示有关系)。(什么,你问我是哪种关系,我也不知道,你自己看题目要求QWQ~~)


性质

研究二元关系时,我们常常关注以下这些特殊的性质:

  1. 自反性(reflexive):
    \((\forall a \in S) \; aRa\)

  2. 反自反性(irreflexive, anti-reflexive):
    \((\forall a \in S) \; \neg(aRa)\)

  3. 对称性(symmetric):
    \((\forall a, b \in S) \; aRb \iff bRa\)

  4. 反对称性(antisymmetric):
    \((\forall a, b \in S) \; (aRb \land bRa) \implies a = b\)

  5. 传递性(transitive):
    \((\forall a, b, c \in S) \; (aRb \land bRc) \implies aRc\)

  6. 连接性(connected):
    \((\forall a, b \in S) \; a \neq b \implies (aRb \lor bRa)\)
    (若 \(aRb \lor bRa\),则称 \(a\)\(b\)可达的。)

  7. 不可比的传递性(transitive of incomparability):
    \((\forall a, b, c \in S) \; \big( \neg(aRb \lor bRa) \land \neg(bRc \lor cRb) \big) \implies \neg(aRc \lor cRa)\)
    (若 \(\neg(aRb \lor bRa)\),则称 \(a\)\(b\)不可比的。)

分类(只讲偏序)

根据各种二元关系所具有的性质,我们可以对二元关系进行分类,最常见的是偏序(partial order)和全序(total order)。

§ 偏序(partial order):满足自反性、反对称性和传递性的二元关系,即:

  • \((\forall a \in S) \, aRa\)
  • \((\forall a, b \in S) \, (aRb \land bRa) \implies a = b\)
  • \((\forall a, b, c \in S) \, (aRb \land bRc) \implies aRc\)

其对应的定义域被称为偏序集。

数点

\(k\) 维数点问题,即在一个由 \(n\)\(k\) 元组构成的集合
\(\{(a_{1,1}, \dots, a_{1,k}), \dots, (a_{n,1}, \dots, a_{n,k})\}\) 中,求满足下列条件的 \(k\) 元组 \((a_{j,1}, \dots, a_{j,k})\) 的个数 / 权值和:

  • \(l_1 \le a_{j,1} \le r_1\)
  • \(\dots\)
  • \(l_n \le a_{j,n} \le r_n\)

可以理解为在 \(k\) 维平面上给定若干点,查询某个区域内点的个数。


通常情况下偏序问题和数点问题是可以互相转换的

三维偏序/陌上花开 题解(CDQ分治解法)

众所周知,这道题可以用无数种办法干过,biteset可以25行过掉,已严惩畏惧。

题意理解

n个元素,每个元素有a、b、c三个特征值,\(f(i)\) 表示满足 \(a_j \leq a_i\)\(b_j \leq b_i\)\(c_j \leq c_i\)\(j \neq i\) 的数的数量。主要在于求偏序个数。

复杂度分析

如果我们暴力做这个问题,显然可以for循环搞出来,复杂度为 \(O(n^2k)\)
显然对于 \(n = 1e5\) 的本意无法通过,而接下来我们 CDQ 分治时间复杂度就很快了,大概是一个 \(O(n \log^2 n)\) 的复杂度。

解题思路

首先对于这个问题,本质是是一个三维的比较问题,我们对于第一位进行排序,此时第一维就已经有序了 \(a_i \leq a_j\) 已保证,相当于降了一维,接下来是对于剩下两维的处理。

我们用分治来处理第二维,从 \([1, n]\) 开始逐层递归。
具体来说,对于子问题 \([l, r]\)

  • \(mid\)\(l, r\) 中点。
  • 递归解决 \([l, mid]\)\([mid + 1, r]\)
  • 统计 \([l, mid]\)\([mid + 1, r]\) 的贡献。

对于第三步直接双指针,令 \(i \in [l, mid], j \in [mid + 1, r]\)。目前我们还需要统计符合 \(b_i \leq b_j, c_i \leq c_j\) 的点对个数。
我们可以枚举 \(j\),看看有多少符合,于是在 \(j\) 指针统计贡献时,左区间即之前所有i计入的贡献已经满足了 \(a_j \leq a_i\)\(b_j \leq b_i\) 的条件,怎么统计 \(c_j \leq c_i\) 的个数呢?

需要单点修改与前缀查询,选择树状数组。可以在值域上开树状数组(BIT),将 \(c_i\) 压入 \(BIT\) ,查询 \(c_j\) 就直接求 \(sum[0 , c_j)\)

code

#include<bits/stdc++.h>
using namespace std;const int N = 2e5+10;struct point{int a,b,c;int cnt;int ans; point() : cnt(1),ans(0){};
}q[N],tmp[N];bool operator == (const point &x,const point &y){return x.a==y.a && x.b==y.b && x.c==y.c;
}int n,k;
int c[N];
int r_ans[N];int lowbit(int x) {return x & -x;}
void adde(int pos,int val){while(pos<=k){c[pos]+=val;pos+=lowbit(pos);}
}
int query(int pos){int ret=0;while(pos){ret+=c[pos];pos-=lowbit(pos);}return ret;
}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,k=l;while(i<=mid && j<=r){if(q[i].b<=q[j].b){adde(q[i].c,q[i].cnt);tmp[k++]=q[i++];}else{q[j].ans+=query(q[j].c);tmp[k++]=q[j++];}}while(i<=mid){adde(q[i].c,q[i].cnt);tmp[k++]=q[i++];}while(j<=r){q[j].ans+=query(q[j].c);tmp[k++]=q[j++];}for(int i=l;i<=mid;i++) adde(q[i].c,-q[i].cnt);for(int i=l;i<=r;i++) q[i]=tmp[i];return;
}int main(){cin.tie(0)->sync_with_stdio(0);cin>>n>>k;for(int i=1;i<=n;i++){cin>>q[i].a>>q[i].b>>q[i].c;}sort(q+1,q+n+1,[](const point &x,const point &y){if(x.a != y.a) return x.a < y.a;if(x.b != y.b) return x.b < y.b;return x.c < y.c;});int idx=0;for(int i=1;i<=n;i++){if(q[i]==q[i-1]){q[idx].cnt++;}else{q[++idx]=q[i];}}cdq(1,idx);for(int i=1;i<=idx;i++){r_ans[q[i].cnt+q[i].ans]+=q[i].cnt;}for(int i=1;i<=n;i++) cout<<r_ans[i]<<"\n";return 0;
}

笔者学习时疑问一

对于第二维第三步你可能会有一些疑问,我们本身第一维已经拍好序了为什么到了第二维反而要用双指针破坏第一维a的顺序呢,这就体现出来了 CDQ 分治的精妙之处,我们把一个大问题拆成了诸多小问题,会发现向下拆分的过程中并没有进行操作,在向上合并的过程中才有操作,我们只需要保证当前层是有序的就不会有影响,当前层的答案是无后效性的,如果你也有过与笔者同样的疑问,那请你停下来仔细思考这个地方是没有问题的。

笔者学习时疑问二

对于第二维的操作我们在合并排序时让左区间的加入树状数组,右区间的查询,笔者在想会不会漏掉一些情况。

  1. 左区间不查询是因为在左区间的子区间中已经统计过。
  2. 右区间能询问完全。分两种情况:a.合并时右区间的加入就会查询。b.没有用到的右区间是为满足所有第二位条件的,会在最后归并完全部查询。

笔者学习时疑问三

对于左区间如果有多的点为什么还要压入树状数组,而非直接跳过。

其实本质上就是直接跳过,他没有被统计,之后树状数组也会清空,多出的点跑完的价值在于填满tmp数组。

http://www.jsqmd.com/news/577358/

相关文章:

  • 从Flux到SD3:聊聊扩散模型‘加速’竞赛背后的CFG蒸馏技术
  • 2026年环球出国深度解析:全球身份规划服务的网络布局与专业支撑 - 品牌推荐
  • 树状数组实战:5个LeetCode高频题解与优化技巧(附Python/Java代码)
  • MaxENT模型结果美化不求人:手把手教你用MATLAB自定义ROC与Omission曲线样式(附配色方案)
  • 深入Linuxptp:ptp4l与E2E模式下的状态机与报文处理流程剖析
  • 安卓手机与HC-05蓝牙模块通信:从硬件连接到数据互传的完整指南
  • OpenSSL实战指南:在VSCode中搭建C语言开发环境
  • 从网球场到棋盘:深入对比Moravec与Forstner算子在真实影像中的表现差异与选型建议
  • 别再傻傻分不清!ComfyUI里Load Checkpoint和Load Diffusion Model到底怎么选?附实战场景对比
  • 2026全科主治医师考试,备考机构哪家强?4大热门机构深度测评 - 医考机构品牌测评专家
  • 实战指南:使用iperf3-win-builds精准诊断Windows网络性能瓶颈
  • Ubuntu18.04下VitisAI 1.2环境搭建全攻略(含Petalinux配置避坑指南)
  • AI写教材攻略:低查重秘诀与优质工具,打造完美教材不是梦!
  • Linux下objdump反汇编实战:从二进制文件到可读代码的深度解析
  • 用Matlab+SPM12+DPABI处理rs-fMRI数据:从ABIDE数据集到AAL脑图谱的完整实战
  • 5G/6G智能信道建模的3大架构决策:DeepMIMO-matlab项目技术深度解析
  • stm32点灯失败原因竟然是printf重定向
  • 治疗性绷带隐形眼镜市场洞察:年复合增长率达14.6%
  • FreeRTOS移植避坑指南:解决STM32F4/F1上那些让人头疼的编译错误(附完整配置文件)
  • PDF Guru Anki:打破知识孤岛,打造你的个人记忆中枢
  • 别再让用户下载了!用iframe一行代码搞定PDF、Word、Excel在线预览(附完整配置)
  • Windows DLL注入工具Xenos全攻略:从原理到实践的系统指南
  • [Carla场景构建] 从零部署RoadRunner:环境配置与依赖问题全解析
  • 别再用requests硬刚了!用Selenium+Playwright搞定小红书评论爬虫(附完整Cookie处理方案)
  • PayloadCMS 高可用企业级部署架构解析
  • 2026年高精度三维扫描仪推荐:热门扫描仪TOP5全维度测评 - 科技焦点
  • 不同温度下锂枝晶形貌对比图](https://via.placeholder.com/800x400?text=30°C+vs+60°C+枝晶对比
  • Windows 11上Docker Desktop死活绑定不了80端口?别慌,试试这四步(附排查脚本)
  • 打造个人离线书库:番茄小说下载器全场景应用指南
  • 2026长沙翡翠名表抵押机构深度评测报告:长沙翡翠回收/长沙翡翠抵押/长沙虫草回收/长沙钻石回收/长沙铂金回收/选择指南 - 优质品牌商家