# 洛谷P5324 [BJOI2019]删数（线段树）

## 题目描述

>记当前数列长度为 $k$ ，则删掉数列中所有等于 $k$ 的数。

## 数据范围

$1 \le n \le 150000$

## 解题思路

#define ls p << 1
#define rs ls | 1
const int S = 150000, lim = S * 3;
const int N = S << 2;
int mn[N<<2], mnc[N<<2], add[N<<2], cnt[N], a[N], ans, st, m, n;
void Tag(int p, int c) { add[p] += c, mn[p] += c; }
void change(int p, int l, int r, int L, int R, int c) {
if (L <= l && r <= R) return Tag(p, c);
int mid = (l + r) >> 1; spread(p);
if (L <= mid) change(ls, l, mid, L, R, c);
if (R > mid) change(rs, mid + 1, r, L, R, c);
mn[p] = min(mn[ls], mn[rs]);
mnc[p] = (mn[ls] == mn[p] ? mnc[ls] : 0) + (mn[rs] == mn[p] ? mnc[rs] : 0);
}
void build(int p, int l, int r) {
mnc[p] = r - l + 1; if (l == r) return;
int mid = (l + r) >> 1;
build(ls, l, mid), build(rs, mid + 1, r);
}
void query(int p, int l, int r, int L, int R) {
if (L <= l && r <= R) return ans += !mn[p] ? mnc[p] : 0, void();
int mid = (l + r) >> 1; spread(p);
if (L <= mid) query(ls, l, mid, L, R);
if (R > mid) query(rs, mid + 1, r, L, R);
}
int main() {
for (int i = 1;i <= n; ++i) read(a[i]), ++cnt[a[i] += S];
build(1, 1, lim);
for (int i = 1;i <= n; ++i)
if (cnt[st + i]) change(1, 1, lim, st + i - cnt[st + i] + 1, st + i, 1);
for (int i = 1, op, x;i <= m; ++i) {
if (op == 0) {
if (x == 1) { if (cnt[st + n]) change(1, 1, lim, st + n - cnt[st + n] + 1, st + n, -1); --st; }
else { ++st; if (cnt[st + n]) change(1, 1, lim, st + n - cnt[st + n] + 1, st + n, 1); }
}
else {
int t = a[op];
if (t <= st + n) change(1, 1, lim, t - cnt[t] + 1, t, -1);
if (--cnt[t] && t <= st + n) change(1, 1, lim, t - cnt[t] + 1, t, 1);
t = a[op] = x + st;
if (cnt[t]) change(1, 1, lim, t - cnt[t] + 1, t, -1);
cnt[t]++, change(1, 1, lim, t - cnt[t] + 1, t, 1);
}
ans = 0, query(1, 1, lim, st + 1, st + n), write(ans);
}
return 0;
}

posted @ 2021-01-24 18:51  Hs-black  阅读(94)  评论(0编辑  收藏  举报