莫队2 这次需要带修改了

莫队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;
  }
}
posted @ 2024-12-13 01:36  指针神教教主Defad  阅读(7)  评论(0编辑  收藏  举报