莫队2 这次需要带修改了
莫队1 走上骗分之路
实现修改
莫队是不支持修改的, 但是有后人加以改进, 就有了代修版本.
我们现在有一个东西叫时间轴 (类似函数式线段树的每个根都是关于某次之前的根修改或查询的), 每次询问都记录一下当前的时间轴, 每次修改都在时间轴上新建一个版本.
typedef struct _qryy {int l, r;int t, i;
} qryy;
这次要可以 \(O(1)\) 给 \(([l, r], t)\) 扩展到 \(([l \pm 1, r], t)\), \(([l, r \pm 1], t)\) 和 \(([l, r], t \pm 1)\).
现在的排序第一关键字是 \(l\) 所在的块, 第二关键字是 \(r\), 第三关键字是 \(t\).
然后在记录修改的位置和值.
typedef struct _updd {int x, k;
} updd;
这次举例单点修区间和
1 x k
\(a_{x} := a_{x} + k\)
2 x y
求 \(\displaystyle \sum_{i \in [x, y]} a_{i}\)
树状数组1.
显然这是树状数组/线段树板子, 但是我们还是在讨论莫队.
VJudge LuoGu
由于莫队本身复杂度玄学, Defad只得到了 70 分, 当然也可能是Defad在分块时分的不够好或各种玄学优化不会, 得分比Defad高可以在评论区发一下您怎么优化的.
int cmp(const void *a, const void *b) {qryy *x = (qryy*)(a), *y = (qryy*)(b);if (pos[x->l] ^ pos[y->l]) {return x->l - y->l;} else if (pos[x->r] ^ pos[y->r]) {return pos[x->r] - pos[y->r];} else {return x->t - y->t;}
}void get_ans() {int l = 1, r = 0, t = 0;qsort(q + 1, cntq, sizeof(q[0]), cmp);f1 (i, 1, cntq, 1) {while (l < q[i].l) {s -= a[l] + upd[l];l++;}while (q[i].l < l) {l--;s += a[l] + upd[l];}while (r < q[i].r) {r++;s += a[r] + upd[r];}while (q[i].r < r) {s -= a[r] + upd[r];r--;}while (t < q[i].t) {t++;if (q[i].l <= c[t].x && c[t].x <= q[i].r) {s += c[t].k; // 更新 sum}upd[c[t].x] += c[t].k; // 版本前进}while (q[i].t < t) {if (q[i].l <= c[t].x && c[t].x <= q[i].r) {s -= c[t].k; // 更新 sum}upd[c[t].x] -= c[t].k; // 版本回退t--;}ans[q[i].i] = s;}
}
例题
VJudge LuoGu
例题也差不多, 但是单点赋值和单点加不同, 单点赋值可以给点值和修改值交换, 下次版本回退可以在换回来.
本题似乎块长开到 \(N^{\cfrac{2}{3}}\) 并且在排序时看 \(l\) 所在块和 \(r\) 所在块和 \(t\) 才可通过.
int cmp(const void *a, const void *b) {qryy *x = (qryy*)(a), *y = (qryy*)(b);if (pos[x->l] ^ pos[y->l]) {return x->l - y->l;
//} else if (x->r ^ y->r) { // 用这个相比下方的会TLE
// return x->r - y->r;} else if (pos[x->r] ^ pos[y->r]) {return pos[x->r] - pos[y->r];} else {return x->t - y->t;}
}void get_ans() {int l = 1, r = 0, t = 0;qsort(q + 1, cntq, sizeof(q[0]), cmp);f1 (i, 1, cntq, 1) {while (l < q[i].l) {s -= (--clr[a[l++]] == 0);}while (q[i].l < l) {s += (++clr[a[--l]] == 1);}while (r < q[i].r) {s += (++clr[a[++r]] == 1);}while (q[i].r < r) {s -= (--clr[a[r--]] == 0);}while (t < q[i].t) {t++;if (q[i].l <= c[t].x && c[t].x <= q[i].r) {s -= (--clr[a[c[t].x]] == 0);s += (++clr[c[t].k] == 1);}c[t].k ^= a[c[t].x];a[c[t].x] ^= c[t].k;c[t].k ^= a[c[t].x];}while (q[i].t < t) {if (q[i].l <= c[t].x && c[t].x <= q[i].r) {s -= (--clr[a[c[t].x]] == 0);s += (++clr[c[t].k] == 1);}c[t].k ^= a[c[t].x];a[c[t].x] ^= c[t].k;c[t].k ^= a[c[t].x];t--;}ans[q[i].i] = s;}
}