向量化线段树
masonxiong · · 算法·理论
省流:单点加,前缀和,树状数组两倍速度。
核心原理
将下标
将第
设
下面是一个
[00, 10, 36, 78 ] S(1)
[00, 01, 03, 06, 00, 05, 11, 18, 00, 09, 19, 30, 00, 13, 27, 42] S(0)
[01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, 15, 16] a
查询
这些
例如
接下来考虑修改
注意到修改操作中每一层的修改形如"将连续
接下来考虑
下面的代码给出一个示例,实现了
:::info[示例代码]
template <int N>
class WideSGT {
using Vector = int __attribute__((vector_size(32)));
static constexpr int Cacheline = 64;
static constexpr int Block = Cacheline / sizeof(int);
static constexpr int Width = __builtin_ctz(Block);
struct Mask {
alignas(Cacheline) int mask[Block][Block];
constexpr Mask() : mask{} {
for (int u = 0; u < Block; ++u)
for (int v = 0; v < Block; ++v)
mask[u][v] = u < v ? -1 : 0;
}
};
static constexpr int height(int i) {
int result = 1, n = i;
while (n >= Block) {
n >>= Width;
++result;
}
return result;
}
static constexpr int offset(int i) {
int result = 0, n = N;
while (i--) {
n = (n + ~-Block) / Block;
result += n * Block;
}
return result;
}
static constexpr int Size = N;
static constexpr int Height = height(Size);
alignas(Cacheline) int data[static_cast<unsigned>(offset(Height))];
static constexpr Mask mask{};
public:
int sum(int position) {
int result = 0;
for (int i = 0; i < Height; ++i) {
result += data[offset(i) + position];
position >>= Width;
}
return result;
}
void modify(int position, int delta) {
auto vector = Vector{} + delta;
for (int i = 0; i < Height; ++i) {
auto block = (Vector*)&data[offset(i) + (position & -Block)];
auto vmask = (Vector*)&mask.mask[position & ~-Block];
block[0] += vector & vmask[0];
block[1] += vector & vmask[1];
position >>= Width;
}
}
};
:::
效率测试
- 评测机:
Intel(R) Core(TM) Ultra 9 285H - 编译器:
g++ (x86_64-win32-seh-rev0, Built by MinGW-Builds project) 15.2.0 - 编译参数:
-std=c++23 -march=native -mtune=native -Ofast
序列长度
WideSGT:1162.4\space\rm ms Fenwick:2052.3\space\rm ms
两倍速度。伟大无需多言。
:::info[测试代码]
template <int N>
class WideSGT {
using Vector = int __attribute__((vector_size(32)));
static constexpr int Cacheline = 64;
static constexpr int Block = Cacheline / sizeof(int);
static constexpr int Width = __builtin_ctz(Block);
struct Mask {
alignas(Cacheline) int mask[Block][Block];
constexpr Mask() : mask{} {
for (int u = 0; u < Block; ++u)
for (int v = 0; v < Block; ++v)
mask[u][v] = u < v ? -1 : 0;
}
};
static constexpr int height(int i) {
int result = 1, n = i;
while (n >= Block) {
n >>= Width;
++result;
}
return result;
}
static constexpr int offset(int i) {
int result = 0, n = N;
while (i--) {
n = (n + ~-Block) / Block;
result += n * Block;
}
return result;
}
static constexpr int Size = N;
static constexpr int Height = height(Size);
alignas(Cacheline) int data[static_cast<unsigned>(offset(Height))];
static constexpr Mask mask{};
public:
int sum(int position) {
int result = 0;
for (int i = 0; i < Height; ++i) {
result += data[offset(i) + position];
position >>= Width;
}
return result;
}
void modify(int position, int delta) {
auto vector = Vector{} + delta;
for (int i = 0; i < Height; ++i) {
auto block = (Vector*)&data[offset(i) + (position & -Block)];
auto vmask = (Vector*)&mask.mask[position & ~-Block];
block[0] += vector & vmask[0];
block[1] += vector & vmask[1];
position >>= Width;
}
}
};
template <int N>
class Fenwick {
int data[static_cast<unsigned>(N)];
public:
int sum(int position) {
int result = 0;
while (position--) {
result += data[position];
position &= -~position;
}
return result;
}
void modify(int position, int delta) {
while (position < N) {
data[position] += delta;
position |= -~position;
}
}
};
#include <ctime>
#include <random>
#include <iostream>
auto main() -> int {
static constexpr int N = 1E7;
static constexpr int M = 2E7;
static WideSGT<N> tree;
int xorsum = 0;
std::mt19937 rng;
for (int i = M; i--; ) {
tree.modify(rng() % N, 1);
xorsum ^= i ^ tree.sum(rng() % N);
}
std::cerr << "XorSum = " << xorsum << '\n';
std::cout << "Duration = " << std::clock() << " clocks\n";
}
:::