news 2026/4/22 18:14:30

详细揭秘:如何发明小波矩阵

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
详细揭秘:如何发明小波矩阵

目录标题

以静态区间第k kk小为例。

首先假装你会归并树。归并树是啥?其实就是对归并排序的过程建树。先建立一个线段树,再自底向上归并,求出每个节点对应的区间[ l , r ] [l,r][l,r]的所有元素构成的有序序列。

归并树可以慢速二维数点。具体地,我们要查区间[ l , r ] [l,r][l,r]有多少个≤ x \le xx的数,可以直接找到每个线段树节点,对节点上的序列二分一下。时间复杂度是O ( log ⁡ 2 n ) \mathcal{O}(\log^2 n)O(log2n)的。要是直接拿这玩意二分求区间第k kk小,可以做到高贵的O ( log ⁡ 2 n log ⁡ V ) \mathcal{O}(\log^2 n\log V)O(log2nlogV)复杂度,这也太菜了。

究其原因是没有利用好归并树能做二维数点。不妨换维,将下标与值域互换,相当于求:值域在[ l , r ] [l,r][l,r]内的从左到右第k kk个数。这就成功把要二分的东西放到了线段树维护的维度上,那么可以把二分换成线段树二分做到O ( log ⁡ n log ⁡ V ) \mathcal{O}(\log n\log V)O(lognlogV)

还能再给力一点吗?注意到换维过后值域是O ( n ) \mathcal{O}(n)O(n)的了,如果能O ( n ) \mathcal{O}(n)O(n)地对同一层处理出来每个数前面有几个数,那么就能再去掉一个log ⁡ n \log nlogn。于是我们开始思考怎么干这个事情。

方便起见把线段树换成01trie \text{01trie}01trie,这样可以省掉一些讨论。现在每一层的元素个数是O ( n ) \mathcal{O}(n)O(n),值域也是O ( n ) \mathcal{O}(n)O(n),我们当然希望能把同一层的所有数都搓到一起。于是不妨将所有左子树扔到最前面,右子树扔到最后面,然后把序列拼起来。大概是这样:

这个大概叫“蝴蝶变换”。方便起见把左子树方向称为红色,右子树方向称为蓝色。

这个树的结构就可以扔掉了,因为我只需要知道一个位置前面有几个蓝色元素,就能直接推出它在蝴蝶变换后会到哪个地方。现在在线段树二分上的过程可以写成这样:

  • 从第一层开始。
  • 计算[ l , r ] [l,r][l,r]之间的红色元素数量。
  • 若个数≥ k \ge kk,则往红色子树走。否则往蓝色子树走。

我们甚至只需要知道元素个数!所以每一层做一个前缀和即可。代码大概长这样:

inlineintkth(intl,intr,intk){intres=0;l--;for(inti=29;~i;i--){intql=b[i][l],qr=b[i][r],c=(r-qr)-(l-ql);if(c>=k)l-=ql,r-=qr;elseres|=1<<i,k-=c,l=p[i]+ql,r=p[i]+qr;}returnres;}

其中b i b_ibi是第i ii层的前缀和,p i p_ipi是第i ii层的红色元素个数。这样我们就做到了O ( log ⁡ V ) \mathcal{O}(\log V)O(logV)查询。

还能再再再给力一点吗?时间复杂度上很难优化了,但是空间O ( n log ⁡ V ) \mathcal{O}(n\log V)O(nlogV)还是不够看。发现我们只要算1 11的个数,可以压个位,空间复杂度做到O ( n log ⁡ V w ) = O ( n ) \mathcal{O}\left(\frac{n\log V}{w}\right)=\mathcal{O}(n)O(wnlogV)=O(n)

然后你就吊打主席树了。恭喜你发明了小波矩阵!

structBitset{intn;vector<pair<ull,int>>b;Bitset(){}Bitset(vector<ull>a){n=(a.size()>>6)+1,b.resize(n);for(inti=0;i<a.size();i++)b[i>>6].first|=a[i]<<(i&63);for(inti=1;i<n;i++)b[i].second=b[i-1].second+__builtin_popcountll(b[i-1].first);}inlineintask(intk){returnb[k>>6].second+__builtin_popcountll(b[k>>6].first&(1ull<<(k&63))-1);}};structWavelet{intn;array<Bitset,30>b;array<int,30>p;Wavelet(vector<int>a){n=a.size();vector<int>t(n);for(inti=29;~i;i--){vector<ull>tmp(n);intx=0,y=0;for(intj=0;j<n;j++)tmp[j]=a[j]>>i&1;for(intj=0;j<n;j++)(a[j]>>i&1?t[y++]:a[x++])=a[j];b[i]=Bitset(tmp),p[i]=x;for(intj=0;j<y;j++)a[x+j]=t[j];}}inlineintkth(intl,intr,intk){intres=0;l--;for(inti=29;~i;i--){intql=b[i].ask(l),qr=b[i].ask(r),c=(r-qr)-(l-ql);if(c>=k)l-=ql,r-=qr;elseres|=1<<i,k-=c,l=p[i]+ql,r=p[i]+qr;}returnres;}};
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 17:30:21

GLM-4.7-Flash效果展示:4096上下文下多轮会议纪要精准提炼

GLM-4.7-Flash效果展示&#xff1a;4096上下文下多轮会议纪要精准提炼 你有没有遇到过这样的情况&#xff1a;刚开完一场两小时的跨部门会议&#xff0c;桌上堆着密密麻麻的录音转文字稿、手写笔记和PPT截图&#xff0c;而老板下午三点就要一份“重点清晰、逻辑完整、可直接发…

作者头像 李华
网站建设 2026/4/20 22:16:52

Z-Image-ComfyUI云平台推荐:阿里云PAI实测

Z-Image-ComfyUI云平台推荐&#xff1a;阿里云PAI实测 在本地显卡跑不动大模型、租用GPU服务器又怕配置踩坑的当下&#xff0c;一个真正“开箱即用、点开就画”的文生图方案有多珍贵&#xff1f;不是所有云平台都能把60亿参数的Z-Image模型变成你浏览器里一个可拖拽的工作流—…

作者头像 李华
网站建设 2026/4/7 9:39:12

Qwen3-Embedding-0.6B功能全测评,小模型大能量

Qwen3-Embedding-0.6B功能全测评&#xff0c;小模型大能量 1. 为什么0.6B这个“小个子”值得你认真看一眼 很多人看到“0.6B”第一反应是&#xff1a;参数量不到10亿&#xff1f;这能干啥&#xff1f;是不是又一个凑数的小模型&#xff1f; 先别急着划走。这次我们不聊参数大…

作者头像 李华
网站建设 2026/3/24 10:12:51

Open-AutoGLM截图功能实测,界面理解准确率高

Open-AutoGLM截图功能实测&#xff0c;界面理解准确率高 1. 这不是“会说话”的AI&#xff0c;而是“会看会做”的手机助理 你有没有过这样的时刻&#xff1a; 想在小红书搜“最近爆火的露营装备”&#xff0c;但手指刚点开App就卡在首页广告&#xff1b; 想给朋友转发抖音里…

作者头像 李华
网站建设 2026/4/18 9:40:04

ChatGLM-6B开源镜像深度体验:对比HuggingFace手动部署的5大优势

ChatGLM-6B开源镜像深度体验&#xff1a;对比HuggingFace手动部署的5大优势 你是否曾为部署一个大语言模型耗费整整半天&#xff1f;下载权重、配置环境、调试CUDA版本、解决依赖冲突、反复重启服务……最后发现WebUI打不开&#xff0c;日志里全是红色报错&#xff1f;我试过三…

作者头像 李华
网站建设 2026/4/15 18:56:33

小白也能懂的YOLO11:目标检测保姆级教程

小白也能懂的YOLO11&#xff1a;目标检测保姆级教程 你是不是也遇到过这样的问题&#xff1a;想用AI识别图中的人和车&#xff0c;但一看到“YOLO”“backbone”“SPPF”这些词就头皮发麻&#xff1f;下载代码、配环境、改配置、调参数……光是看文档就花了两小时&#xff0c;…

作者头像 李华