Wavelet Matrix
摸个鱼。英语课上研究了一会感觉挺好玩的。
一种基于二进制分解的能在 \(O(\log w)\) 时间内解决静态区间 k 小、区间排名之类的问题的简单数据结构,貌似能套个平衡树拓展到动态。
初始化
从高到低对每一个二进制位进行以下操作:
在矩阵对应行记录一下数组每个数这一位的值。然后将数组按照这一位稳定排序,记录一下 0 和 1 的分割线位置。
(感觉此处有个图能讲得清楚,不过咕)
前缀和也会用到所以预处理下前缀和。不考虑时空常数的话代码就四行:
for(int j=30;~j;--j){
for(int i=1;i<=n;++i)s[j][i]=s[j][i-1]+(a[i]>>j&1);
pos[j]=stable_partition(a+1,a+n+1,[&](int x){return !(x>>j&1);})-a;
}
区间 k 小
首先看第一行没有排过序的,假如区间内 0 的数量(这里前缀和就有用了) \(\ge k\) 那答案这一位肯定是 0,否则是 1。然后由于稳定排序 0 和 1 内部的相对位置固定,当前区间只对应下一层的两个区间,且答案在哪个区间已经知道,所以一直往下走即可。
时空和码量都比主席树优秀。
int kth(int l,int r,int k){
int ret=0;
for(int j=30;~j;--j){
int c=s[j][r]-s[j][l-1];
if(r-l+1-c>=k){
l-=s[j][l-1];
r-=s[j][r];
}
else{
k-=r-l+1-c;
l=pos[j]+s[j][l-1];
r=pos[j]+s[j][r]-1;
ret|=1<<j;
}
}
return ret;
}
区间排名
刚用到了先放一下。
用来实现静态在线矩形数点。以下代码返回 \([l,r]\) 之间 \(<x\) 的数的个数。
int rk(int l,int r,int x){
int ret=0;
for(int j=19;~j;--j){
if(x>>j&1){
ret+=r-l+1-s[j][r]+s[j][l-1];
l=pos[j]+s[j][l-1];
r=pos[j]+s[j][r]-1;
}
else{
l-=s[j][l-1];
r-=s[j][r];
}
}
return ret;
}
咕

浙公网安备 33010602011771号