1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
| SqrtTreeItem op(const SqrtTreeItem &a, const SqrtTreeItem &b);
int log2Up(int n) { int res = 0; while ((1 << res) < n) { res++; } return res; }
class SqrtTree { private: int n, lg, indexSz; vector<SqrtTreeItem> v; vector<int> clz, layers, onLayer; vector<vector<SqrtTreeItem> > pref, suf, between;
void buildBlock(int layer, int l, int r) { pref[layer][l] = v[l]; for (int i = l + 1; i < r; i++) { pref[layer][i] = op(pref[layer][i - 1], v[i]); } suf[layer][r - 1] = v[r - 1]; for (int i = r - 2; i >= l; i--) { suf[layer][i] = op(v[i], suf[layer][i + 1]); } }
void buildBetween(int layer, int lBound, int rBound, int betweenOffs) { int bSzLog = (layers[layer] + 1) >> 1; int bCntLog = layers[layer] >> 1; int bSz = 1 << bSzLog; int bCnt = (rBound - lBound + bSz - 1) >> bSzLog; for (int i = 0; i < bCnt; i++) { SqrtTreeItem ans; for (int j = i; j < bCnt; j++) { SqrtTreeItem add = suf[layer][lBound + (j << bSzLog)]; ans = (i == j) ? add : op(ans, add); between[layer - 1][betweenOffs + lBound + (i << bCntLog) + j] = ans; } } }
void buildBetweenZero() { int bSzLog = (lg + 1) >> 1; for (int i = 0; i < indexSz; i++) { v[n + i] = suf[0][i << bSzLog]; } build(1, n, n + indexSz, (1 << lg) - n); }
void updateBetweenZero(int bid) { int bSzLog = (lg + 1) >> 1; v[n + bid] = suf[0][bid << bSzLog]; update(1, n, n + indexSz, (1 << lg) - n, n + bid); }
void build(int layer, int lBound, int rBound, int betweenOffs) { if (layer >= (int)layers.size()) { return; } int bSz = 1 << ((layers[layer] + 1) >> 1); for (int l = lBound; l < rBound; l += bSz) { int r = min(l + bSz, rBound); buildBlock(layer, l, r); build(layer + 1, l, r, betweenOffs); } if (layer == 0) { buildBetweenZero(); } else { buildBetween(layer, lBound, rBound, betweenOffs); } }
void update(int layer, int lBound, int rBound, int betweenOffs, int x) { if (layer >= (int)layers.size()) { return; } int bSzLog = (layers[layer] + 1) >> 1; int bSz = 1 << bSzLog; int blockIdx = (x - lBound) >> bSzLog; int l = lBound + (blockIdx << bSzLog); int r = min(l + bSz, rBound); buildBlock(layer, l, r); if (layer == 0) { updateBetweenZero(blockIdx); } else { buildBetween(layer, lBound, rBound, betweenOffs); } update(layer + 1, l, r, betweenOffs, x); }
SqrtTreeItem query(int l, int r, int betweenOffs, int base) { if (l == r) { return v[l]; } if (l + 1 == r) { return op(v[l], v[r]); } int layer = onLayer[clz[(l - base) ^ (r - base)]]; int bSzLog = (layers[layer] + 1) >> 1; int bCntLog = layers[layer] >> 1; int lBound = (((l - base) >> layers[layer]) << layers[layer]) + base; int lBlock = ((l - lBound) >> bSzLog) + 1; int rBlock = ((r - lBound) >> bSzLog) - 1; SqrtTreeItem ans = suf[layer][l]; if (lBlock <= rBlock) { SqrtTreeItem add = (layer == 0) ? (query(n + lBlock, n + rBlock, (1 << lg) - n, n)) : (between[layer - 1][betweenOffs + lBound + (lBlock << bCntLog) + rBlock]); ans = op(ans, add); } ans = op(ans, pref[layer][r]); return ans; }
public: SqrtTreeItem query(int l, int r) { return query(l, r, 0, 0); }
void update(int x, const SqrtTreeItem &item) { v[x] = item; update(0, 0, n, 0, x); }
SqrtTree(const vector<SqrtTreeItem> &a) : n((int)a.size()), lg(log2Up(n)), v(a), clz(1 << lg), onLayer(lg + 1) { clz[0] = 0; for (int i = 1; i < (int)clz.size(); i++) { clz[i] = clz[i >> 1] + 1; } int tlg = lg; while (tlg > 1) { onLayer[tlg] = (int)layers.size(); layers.push_back(tlg); tlg = (tlg + 1) >> 1; } for (int i = lg - 1; i >= 0; i--) { onLayer[i] = max(onLayer[i], onLayer[i + 1]); } int betweenLayers = max(0, (int)layers.size() - 1); int bSzLog = (lg + 1) >> 1; int bSz = 1 << bSzLog; indexSz = (n + bSz - 1) >> bSzLog; v.resize(n + indexSz); pref.assign(layers.size(), vector<SqrtTreeItem>(n + indexSz)); suf.assign(layers.size(), vector<SqrtTreeItem>(n + indexSz)); between.assign(betweenLayers, vector<SqrtTreeItem>((1 << lg) + bSz)); build(0, 0, n, 0); } };
|