news 2026/10/13 16:57:14

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

作者头像

张小明

前端开发工程师

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

目录标题

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

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

归并树可以慢速二维数点。具体地,我们要查区间[ l , r ] [l,r][l,r]有多少个≤ x \le x≤x的数,可以直接找到每个线段树节点,对节点上的序列二分一下。时间复杂度是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 k≥k,则往红色子树走。否则往蓝色子树走。

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

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/10/12 21:16:16

HY-Motion 1.0生产就绪:健康检查、日志追踪、性能监控一体化运维方案

HY-Motion 1.0生产就绪&#xff1a;健康检查、日志追踪、性能监控一体化运维方案 1. 为什么动作生成需要“生产级”运维能力&#xff1f; 你有没有试过——模型本地跑通了&#xff0c;提示词写得漂亮&#xff0c;生成的动作也流畅自然&#xff0c;可一上服务器就卡在加载权重…

作者头像 李华
网站建设 2026/10/9 21:06:41

低成本GPU部署Qwen3-VL-2B-Instruct实战,显存优化技巧详解

低成本GPU部署Qwen3-VL-2B-Instruct实战&#xff0c;显存优化技巧详解 1. 为什么选Qwen3-VL-2B-Instruct&#xff1f;轻量、全能、真能跑 很多人一看到“视觉-语言大模型”&#xff0c;第一反应是&#xff1a;得上A100/H100吧&#xff1f;显存不够&#xff1f;推理卡顿&#…

作者头像 李华
网站建设 2026/10/11 13:28:14

WuliArt Qwen-Image Turbo保姆级教程:LoRA权重热加载与WebUI风格切换开发

WuliArt Qwen-Image Turbo保姆级教程&#xff1a;LoRA权重热加载与WebUI风格切换开发 1. 为什么你需要这个教程 你是不是也遇到过这些问题&#xff1a; 下载了一个漂亮的LoRA模型&#xff0c;却要重启整个WebUI才能生效&#xff1f;等30秒加载、清缓存、重开浏览器…生成一张…

作者头像 李华
网站建设 2026/10/7 0:41:26

Qwen3-VL-8B开源可部署优势解析:完全离线运行,无API调用依赖

Qwen3-VL-8B开源可部署优势解析&#xff1a;完全离线运行&#xff0c;无API调用依赖 你是否厌倦了每次调用AI服务都要联网、等响应、看配额、担心隐私泄露&#xff1f;是否试过在没有网络的会议室、工厂车间或科研外场&#xff0c;想快速验证一个图文理解想法却束手无策&#…

作者头像 李华
网站建设 2026/10/12 22:45:15

教育场景语音分析:用SenseVoiceSmall识别学生情绪变化

教育场景语音分析&#xff1a;用SenseVoiceSmall识别学生情绪变化 【免费下载链接】SenseVoiceSmall 多语言语音理解模型&#xff08;富文本/情感识别版&#xff09; 项目地址&#xff1a;https://modelscope.cn/models/iic/SenseVoiceSmall 课堂上&#xff0c;一个学生低头不…

作者头像 李华
网站建设 2026/10/10 22:24:27

从零实现基于ModbusRTU的远程I/O控制项目

以下是对您提供的技术博文进行 深度润色与工程化重构后的终稿 。全文已彻底去除AI生成痕迹,强化了真实开发语境下的经验感、教学逻辑与可复用性;结构上打破传统“引言-正文-总结”套路,以问题驱动为主线自然展开;语言更贴近一线嵌入式工程师的表达习惯——有判断、有取舍…

作者头像 李华