题解:P12485 [集训队互测 2024] PM 大师
写这个题跟用户名没啥关系。
设
从值域考虑,不难发现对于非
查询
考虑如何处理修改。每次将
同样用线段树维护,区间内维护 set 或者懒删除的堆维护。时间复杂度为
:::success[主要代码]
int n, q, a[MAXN], pre[MAXN], val[MAXN];
bool vis[MAXN];
priority_queue<int, vector<int>, greater<>> Q[MAXN];
struct SegTree {
#define ls(p) (p << 1)
#define rs(p) (p << 1 | 1)
struct Node {
int mn, mnp, mx, mxp, cnt;
Node &operator+=(const Node &rhs) {
if (rhs.mn < mn) {
mn = rhs.mn;
mnp = rhs.mnp;
}
if (rhs.mx > mx) {
mx = rhs.mx;
mxp = rhs.mxp;
}
cnt += rhs.cnt;
return *this;
}
friend Node operator+(Node lhs, const Node &rhs) {
return lhs += rhs;
}
} nd[MAXN << 2];
int tg[MAXN << 2];
void build(int p, int l, int r) {
if (l == r) {
nd[p] = {inf, 0, -inf, 0, 0};
if (val[l] > 0) {
vis[l] = false;
nd[p].mn = val[l];
nd[p].mnp = l;
} else {
vis[l] = true;
nd[p].mx = val[l];
nd[p].mxp = l;
nd[p].cnt = 1;
}
return;
}
int mid = l + r >> 1;
build(ls(p), l, mid);
build(rs(p), mid + 1, r);
pushUp(p);
}
void pushUp(int p) {
nd[p] = nd[ls(p)] + nd[rs(p)];
}
void applyAdd(int p, int v) {
tg[p] += v;
if (nd[p].mn != inf) nd[p].mn += v;
if (nd[p].mx != -inf) nd[p].mx += v;
}
void pushDown(int p) {
if (!tg[p]) return;
applyAdd(ls(p), tg[p]);
applyAdd(rs(p), tg[p]);
tg[p] = 0;
}
int query(int p, int l, int r, int x) {
if (l == r) return vis[l] ? nd[p].mx : nd[p].mn;
pushDown(p);
int mid = l + r >> 1;
return x <= mid ? query(ls(p), l, mid, x) : query(rs(p), mid + 1, r, x);
}
void upd(int p, int l, int r, int x) {
if (l == r) {
if (nd[p].mn <= 0) {
nd[p].mx = nd[p].mn;
nd[p].mn = inf;
swap(nd[p].mnp, nd[p].mxp);
} else if (nd[p].mx > 0) {
nd[p].mn = nd[p].mx;
nd[p].mx = -inf;
swap(nd[p].mnp, nd[p].mxp);
}
nd[p].cnt = vis[l];
return;
}
pushDown(p);
int mid = l + r >> 1;
if (x <= mid) upd(ls(p), l, mid, x);
else upd(rs(p), mid + 1, r, x);
pushUp(p);
}
void add(int p, int l, int r, int x, int y, int v) {
if (x <= l && y >= r) {
applyAdd(p, v);
return;
}
pushDown(p);
int mid = l + r >> 1;
if (x <= mid) add(ls(p), l, mid, x, y, v);
if (y > mid) add(rs(p), mid + 1, r, x, y, v);
pushUp(p);
}
int find(int p, int l, int r, int k) {
if (l == r) return l;
pushDown(p);
int mid = l + r >> 1;
return k <= nd[ls(p)].cnt ? find(ls(p), l, mid, k) : find(rs(p), mid + 1, r, k - nd[ls(p)].cnt);
}
#undef ls
#undef rs
} sgt;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> q;
for (int i = 1; i <= n; ++i) {
cin >> a[i];
pre[i] = pre[i - 1] + (a[i] == 0);
}
int m = pre[n];
for (int v = 1, cnt = 0; v <= n; ++v) {
val[v] = v - m - cnt;
if (val[v] > 0) ++cnt;
}
sgt.build(1, 1, n);
while (q--) {
int x, k, y;
cin >> x >> k >> y;
auto getD = [&](int v) {
if (v <= 0) return -1;
while (!Q[v].empty() && a[Q[v].top()] != v) Q[v].pop();
return Q[v].empty() ? m : pre[Q[v].top()];
};
auto upd = [&](int v, int dt) {
int prvVal = sgt.query(1, 1, n, v), nxtVal = prvVal + dt;
sgt.add(1, 1, n, v, v, dt);
if (prvVal > 0 && nxtVal <= 0) {
vis[v] = true;
sgt.upd(1, 1, n, v);
if (v < n) {
sgt.add(1, 1, n, v + 1, n, 1);
if (sgt.nd[1].mx > 0) {
int p = sgt.nd[1].mxp;
vis[p] = false;
sgt.upd(1, 1, n, p);
if (p < n) sgt.add(1, 1, n, p + 1, n, -1);
}
}
} else if (prvVal <= 0 && nxtVal > 0) {
vis[v] = false;
sgt.upd(1, 1, n, v);
if (v < n) {
sgt.add(1, 1, n, v + 1, n, -1);
if (sgt.nd[1].mn <= 0) {
int p = sgt.nd[1].mnp;
vis[p] = true;
sgt.upd(1, 1, n, p);
if (p < n) sgt.add(1, 1, n, p + 1, n, 1);
}
}
}
};
int tmp = a[x], prv1 = getD(tmp), prv2 = getD(k);
a[x] = k;
if (k > 0) Q[k].emplace(x);
int nxt1 = getD(tmp), nxt2 = getD(k);
if (tmp > 0) upd(tmp, prv1 - nxt1);
if (k > 0) upd(k, prv2 - nxt2);
cout << (a[y] ? a[y] : sgt.find(1, 1, n, pre[y])) << '\n';
}
return 0;
}
:::