P6578 [Ynoi2019] 魔法少女网站
比较简单的题目,操作分块做法,并不很卡常。
考虑不带修,这是个经典问题。将小于等于
维护
对于每个块,维护
那么区间查询时,散块暴力,跨越块时继承之前的最长连续
这样写的常数非常小,并且由于维护的信息少,在后续的回滚过程中也有显著常数优势。
有单点修改,那么操作分块。每一块重构
序列分块两边常数差不多,块长直接取 是不是把
注意不要使用任何 vector。用如上方法维护的操作分块做法并不很卡常,块长也可以随便调,码量也较小,轻松跑到了最优解前两页。
AC record
int n, m, a[MAXN], idx[MAXN], len, bcnt, L[BLEN], R[BLEN], chg[MAXN];
int to[MAXN]; ll sum[BLEN], ans[MAXN], prec[MAXN];
struct node {
int op, x, y, k, id;
il bool operator < (const node &p) const {
return k < p.k;
}
} q[MAXN], q1[MAXN], q2[MAXN];
struct rck {
int x; ll s;
int p1, q1, p2, q2;
} cgk[MAXN]; int lcg;
il ll getans(int l, int r) {
int p = idx[l], q = idx[r];
if (q - p < 2) {
ll ans = 0; int cnt = 0;
rep1(i, l, r) to[i] ? ans += ++cnt : cnt = 0;
return ans;
} ll ans = 0; int cnt = 0;
rep1(i, l, R[p]) to[i] ? ans += ++cnt : cnt = 0;
rep1(i, p + 1, q - 1) {
int _l = L[i], _r = R[i];
if (to[_l] == _r) {
int len = _r - _l + 1;
ans += ll(cnt + 1 + cnt + len) * len / 2;
cnt += len;
continue;
}
if (to[_l]) {
int len = to[_l] - _l + 1;
ans -= prec[len];
ans += ll(cnt + 1 + cnt + len) * len / 2;
} ans += sum[i];
if (to[_r]) cnt = _r - to[_r] + 1;
else cnt = 0;
}
rep1(i, L[q], r) to[i] ? ans += ++cnt : cnt = 0;
return ans;
}
il void insert(int x, int o = 1) {
int id = idx[x]; rck g; ll &sn = g.s = 0; g.p1 = g.p2 = 0; g.x = x;
bool flg1 = x != L[id] && to[x - 1], flg2 = x != R[id] && to[x + 1];
if (flg1 && flg2) {
to[x] = 1;
int p = to[x - 1], q = to[x + 1], len = q - p + 1;
g.q1 = to[g.p1 = p]; to[p] = q;
g.q2 = to[g.p2 = q]; to[q] = p;
sn = prec[len] - prec[x - p] - prec[q - x];
} else if (flg1) {
int p = to[x - 1], len = x - p + 1;
g.q1 = to[g.p1 = p];
to[p] = x; to[x] = p; sn = len;
} else if (flg2) {
int p = to[x + 1], len = p - x + 1;
g.q1 = to[g.p1 = p];
to[p] = x; to[x] = p; sn = len;
} else to[x] = x, sn = 1;
o && (cgk[++lcg] = g, 1); sum[id] += sn;
}
il void rollback() {
while (lcg) {
auto [x, s, p1, q1, p2, q2] = cgk[lcg--];
sum[idx[x]] -= s; to[x] = 0;
p1 && (to[p1] = q1); p2 && (to[p2] = q2);
}
}
int tot, pnt[MAXN];
struct edge {
int to, nxt;
} G[MAXN];
il void add(const int &x, const int &y) {
G[++tot] = {y, pnt[x]}; pnt[x] = tot;
}
int main() {
read(n, m); rer(i, 1, n, a);
rep1(i, 1, n) prec[i] = prec[i - 1] + i;
rep1(i, 1, m) {
read(q[i].op, q[i].x, q[i].y); q[i].id = i;
if (q[i].op == 2) read(q[i].k);
} len = sqrt(n); bcnt = (n - 1) / len + 1;
rep1(i, 1, n) idx[i] = (i - 1) / len + 1;
rep1(i, 1, bcnt) L[i] = R[i - 1] + 1, R[i] = L[i] + len - 1;
R[bcnt] = n; int qlen = sqrt(11 * m);
rep1(bid, 1, (m - 1) / qlen + 1) {
int L = (bid - 1) * qlen + 1, R = min(L + qlen - 1, m), len1 = 0, len2 = 0;
memset(to, 0, sizeof(int) * (n + 5)); memset(chg, 0, sizeof(int) * (n + 5));
memset(sum, 0, sizeof sum); memset(pnt, 0, sizeof pnt); tot = 0;
rep1(i, L, R) if (q[i].op == 2) q2[++len2] = q[i]; else q1[++len1] = q[i];
sort(q2 + 1, q2 + 1 + len2); int val = 0;
rep1(i, 1, n) add(a[i], i);
rep1(i, 1, len2) {
auto [op, l, r, x, id] = q2[i];
rep1(i, 1, len1) chg[q1[i].x] = 1;
while (val < x) {
++val;
for (int i = pnt[val]; i; i = G[i].nxt) if (!chg[G[i].to]) insert(G[i].to, 0);
}
rep2(i, len1, 1) if (q1[i].id < id && chg[q1[i].x]) q1[i].y <= x && (insert(q1[i].x), 1), chg[q1[i].x] = 0;
rep1(i, 1, len1) if (chg[q1[i].x]) a[q1[i].x] <= x && (insert(q1[i].x), 1), chg[q1[i].x] = 0;
ans[id] = getans(l, r); rollback();
}
rep1(i, L, R) q[i].op == 1 ? a[q[i].x] = q[i].y : (write(ans[i]), putchar('\n'), 1);
}
return 0;
}