[BJOI2019]删数 题解
Solution
虽然要AFO了,但是不妨记录一下最后的日子。/kk
首先可以看出,合法条件就是对于存在的 \(x\),那么 \(\le x\) 的数的个数恰好等于 \(x\),那么我们可以转化一下,相当于对于一个位置 \(i\) 存在 \(x\) 个,那么我们覆盖 \([i-x+1,i]\),如果恰好覆盖了 \([1,n]\),那么就是合法的。考虑最小修改次数,显然就是没有被覆盖到的点数,这玩意可以维护区间最小值及其个数。
注意到单点修改容易操作,考虑整体加减 \(1\),可以发现我们可以通过标记实现。
Code
#include <bits/stdc++.h>
using namespace std;
#define Int register int
#define MAXN 450005
template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> inline void chkmax (T &a,T b){a = max (a,b);}
template <typename T> inline void chkmin (T &a,T b){a = min (a,b);}
int n,m,a[MAXN],up,st;
struct node{
int miv,sum;
node operator + (const node &p)const{
if (miv < p.miv) return *this;
else if (miv == p.miv) return node{miv,sum + p.sum};
else return p;
}
};
struct Segment{
node Sum[MAXN << 2];int tag[MAXN << 2];
void pushadd (int x,int v){Sum[x].miv += v,tag[x] += v;}
void pushdown (int x){pushadd (x << 1,tag[x]),pushadd (x << 1 | 1,tag[x]),tag[x] = 0;}
void pushup (int x){Sum[x] = Sum[x << 1] + Sum[x << 1 | 1];}
void modify (int x,int l,int r,int ql,int qr,int v){
if (l >= ql && r <= qr) return pushadd (x,v);
int mid = l + r >> 1;pushdown (x);
if (ql <= mid) modify (x << 1,l,mid,ql,qr,v);
if (qr > mid) modify (x << 1 | 1,mid + 1,r,ql,qr,v);
pushup (x);
}
void build (int x,int l,int r){
Sum[x] = node{0,r - l + 1};
if (l == r) return ;
int mid = l + r >> 1;
build (x << 1,l,mid),build (x << 1 | 1,mid + 1,r);
}
int query (int x,int l,int r,int ql,int qr){
if (l >= ql && r <= qr) return Sum[x].miv == 0 ? Sum[x].sum : 0;
int mid = l + r >> 1,res = 0;pushdown (x);
if (ql <= mid) res += query (x << 1,l,mid,ql,qr);
if (qr > mid) res += query (x << 1 | 1,mid + 1,r,ql,qr);
return res;
}
}tree;
int b[MAXN];
void change (int x,int c){
int pos = x - b[x] + 1 - (c > 0);
tree.modify (1,1,up,pos,pos,c),b[x] += c;
}
signed main(){
read (n,m),up = 4.5e5 + 1,st = 1.5e5 + 1,tree.build (1,1,up);
for (Int i = 1;i <= n;++ i) read (a[i]),a[i] += st,change (a[i],1);
while (m --> 0){
int p,x;read (p,x);
if (p){
if (a[p] <= st + n) change (a[p],-1);
else b[a[p]] --;
a[p] = st + x;
if (a[p] <= st + n) change (a[p],1);
else b[a[p]] ++;
}
else{
if (x == 1 && b[st + n]) tree.modify (1,1,up,st + n - b[st + n] + 1,st + n,-1);
st -= x;
if (x == -1 && b[st + n]) tree.modify (1,1,up,st + n - b[st + n] + 1,st + n,1);
}
write (tree.query (1,1,up,st + 1,st + n)),putchar ('\n');
}
return 0;
}