A. Balanced Bitstring
略
B. Tree Tag
略
C. Fixed Point Removal
先考虑对固定的数组 a a a如何求解。显然如果某个初始的 i < a i i<a_i i<ai一定不可移除,否则我们为了移除它,需要某个时刻在 [ 1 , i − 1 ] [1,i-1] [1,i−1]之间移除恰好 i − a i i-a_i i−ai个。那么我们从左到右扫描,记录当前可移除的最大个数 s u m sum sum,若 i ≥ a i i\geq a_i i≥ai且 s u m ≥ i − a i sum\geq i-a_i sum≥i−ai就意味着可以移除 a i a_i ai,将 s u m sum sum增加 1 1 1。最后构造方案是容易的,只需每次移除可移除的最后一个数即可。
现在还要将一个前缀和后缀变为不可移除。我们考虑对 x x x从大到小扫描,每次将某个 a i a_i ai变为可以移除的话,会引起连锁反应,将后面一些 a i a_i ai变为可以移除。用一个线段树维护当前后缀中还未能移除且 i − a i > 0 i-a_i>0 i−ai>0的数分别还需要前面移除多少个数,那么每次即为后缀减 1 1 1,查询权值 ≤ 0 \leq 0 ≤0的最小位置。而 y y y的影响仅是一个求前缀和,用树状数组维护当前可以移除的位置集合即可。
时间复杂度为 O ( ( n + q ) log n ) \mathcal O((n+q)\log n) O((n+q)logn)。
#include <bits/stdc++.h>
#define lowbit(x) (x&-x)
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
namespace BIT {
int sumv[300005];
void add(int x,int n) {
for(;x<=n;x+=lowbit(x)) sumv[x]++;
}
int sum(int x) {
int s=0;
for(;x;x-=lowbit(x)) s+=sumv[x];
return s;
}
}
namespace SGT {
int addv[1200000],minn[1200000];
inline void pushdown(int o) {
if (addv[o]) {
addv[o*2]+=addv[o];
addv[o*2+1]+=addv[o];
minn[o*2]-=addv[o];
minn[o*2+1]-=addv[o];
addv[o]=0;
}
}
inline void pushup(int o) {
minn[o]=min(minn[o*2],minn[o*2+1]);
}
void init() {
memset(minn,0x3f,sizeof(minn));
}