Appearance
Sqrt Tree 可以
但是采用 vector 实现常数貌似有点太大了,码量也很大,仅供参考。娱乐性大于实用性。
询问:
考虑序列分块,将原序列分成
不妨将询问区间在同一块内的情况继续递归下去,若每次询问区间不在同一块内,都是
因为每次递归分块长度都是
考虑将这个递归的过程建成一棵树,每个节点都有
那么递归的过程就是自下而上找到第一层存在完全包含于询问区间的块,这个过程可以二分,此时时间复杂度降至
通过调整块长还可继续优化,假设每一层快长都为
关于块长
实际维护的时候,不用显式建树,只要维护若干层的分块即可。
cpp
struct sqr_tree {
int k;
vector<vector<vector<int>>> B;
vector<vector<int>> pre, suf;
int id(int x) { return (x - 1) / (1 << k) + 1; }
int l(int x) { return (1 << k) * (x - 1) + 1; }
int r(int x) { return (1 << k) * x; }
void init(int k, int n, vector<int> &a, bool w) {
this->k = k;
int idx = id(n);
for (int i = 1; i <= idx; i++) {
vector<int> temp;
int l = this->l(i), r = this->r(i);
for (int j = l; j <= r; j++) {
if (temp.empty())
temp.push_back(a[j]);
else
temp.push_back(max(a[j], temp.back()));
}
pre.push_back(temp);
temp.clear();
for (int j = r; j >= l; j--) {
if (temp.empty())
temp.push_back(a[j]);
else
temp.push_back(max(a[j], temp.back()));
}
suf.push_back(temp);
}
if (!w) {
vector<vector<int>> tmp;
for (int i = 1; i <= idx; i++) {
vector<int> temp;
for (int j = i; j <= idx; j++) {
if (temp.empty())
temp.push_back(pre[j - 1].back());
else
temp.push_back(max(pre[j - 1].back(), temp.back()));
}
tmp.push_back(temp);
}
B.push_back(tmp);
} else {
for (i = 1; i <= n; i += (1 << (k + k))) {
int now = id(i), cur = id(i + (1 << (k + k)) - 1);
vector<vector<int>> tmp;
for (int j = now; j <= cur; j++) {
vector<int> temp;
for (int l = j; l <= cur; l++) {
if (temp.empty())
temp.push_back(pre[l - 1].back());
else
temp.push_back(max(pre[l - 1].back(), temp.back()));
}
tmp.push_back(temp);
}
B.push_back(tmp);
}
}
}
bool in(int l, int r) { return (l ^ r) < (1 << k); }
int query(int l, int r, int w) {
int res = 0;
if (!w) {
int s = id(l) + 1, t = id(r) - 1;
if (s <= t)
res = B[0][s - 1][t - s];
s--, t++;
res = max(res, suf[s - 1][this->r(s) - l]);
res = max(res, pre[t - 1][r - this->l(t)]);
return res;
} else {
int index = (l - 1) / (1 << (k + k));
int s = id(l), t = id(r);
res = max(res, suf[s - 1][this->r(s) - l]);
res = max(res, pre[t - 1][r - this->l(t)]);
s++, t--;
if (s <= t) {
s = (s - 1) % (1 << k) + 1;
t = (t - 1) % (1 << k) + 1;
res = max(res, B[index][s - 1][t - s]);
}
return res;
}
}
} tree[10];可以发现,Sqrt Tree 维护信息的本质是首尾前后缀和中间整块信息预处理,和猫树是类似的。不难意识到:Sqrt Tree 在功能性上优于猫树优于 ST 表。但是常数上显然 Sqrt Tree 大于猫树大于 ST 表,所以就实际表现而言,Sqrt Tree 并不见得有多大优势。
甚至 Sqrt Tree 在不影响预处理和询问的前提下,支持
修改:
感觉有点复杂,主要是没啥用。暂时略了,真遇到了再说。
