莫队2 这次需要带修改了
莫队2 这次需要带修改了
实现修改
莫队是不支持修改的, 但是有后人加以改进, 就有了代修版本.
我们现在有一个东西叫时间轴 (类似函数式线段树的每个根都是关于某次之前的根修改或查询的), 每次询问都记录一下当前的时间轴, 每次修改都在时间轴上新建一个版本.
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.
显然这是树状数组/线段树板子, 但是我们还是在讨论莫队.
由于莫队本身复杂度玄学, 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;
}
}
例题
例题也差不多, 但是单点赋值和单点加不同, 单点赋值可以给点值和修改值交换, 下次版本回退可以在换回来.
本题似乎块长开到 \(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;
}
}
原文来自CnBlogs, 作者: 指针神教教主Defad.